1 //===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This code rewrites include invocations into their expansions. This gives you 10 // a file with all included files merged into it. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Rewrite/Frontend/Rewriters.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "clang/Frontend/PreprocessorOutputOptions.h" 17 #include "clang/Lex/Pragma.h" 18 #include "clang/Lex/Preprocessor.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <optional> 22 23 using namespace clang; 24 using namespace llvm; 25 26 namespace { 27 28 class InclusionRewriter : public PPCallbacks { 29 /// Information about which #includes were actually performed, 30 /// created by preprocessor callbacks. 31 struct IncludedFile { 32 FileID Id; 33 SrcMgr::CharacteristicKind FileType; 34 IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType) 35 : Id(Id), FileType(FileType) {} 36 }; 37 Preprocessor &PP; ///< Used to find inclusion directives. 38 SourceManager &SM; ///< Used to read and manage source files. 39 raw_ostream &OS; ///< The destination stream for rewritten contents. 40 StringRef MainEOL; ///< The line ending marker to use. 41 llvm::MemoryBufferRef PredefinesBuffer; ///< The preprocessor predefines. 42 bool ShowLineMarkers; ///< Show #line markers. 43 bool UseLineDirectives; ///< Use of line directives or line markers. 44 /// Tracks where inclusions that change the file are found. 45 std::map<SourceLocation, IncludedFile> FileIncludes; 46 /// Tracks where inclusions that import modules are found. 47 std::map<SourceLocation, const Module *> ModuleIncludes; 48 /// Tracks where inclusions that enter modules (in a module build) are found. 49 std::map<SourceLocation, const Module *> ModuleEntryIncludes; 50 /// Tracks where #if and #elif directives get evaluated and whether to true. 51 std::map<SourceLocation, bool> IfConditions; 52 /// Used transitively for building up the FileIncludes mapping over the 53 /// various \c PPCallbacks callbacks. 54 SourceLocation LastInclusionLocation; 55 public: 56 InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, 57 bool UseLineDirectives); 58 void Process(FileID FileId, SrcMgr::CharacteristicKind FileType); 59 void setPredefinesBuffer(const llvm::MemoryBufferRef &Buf) { 60 PredefinesBuffer = Buf; 61 } 62 void detectMainFileEOL(); 63 void handleModuleBegin(Token &Tok) { 64 assert(Tok.getKind() == tok::annot_module_begin); 65 ModuleEntryIncludes.insert( 66 {Tok.getLocation(), (Module *)Tok.getAnnotationValue()}); 67 } 68 private: 69 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 70 SrcMgr::CharacteristicKind FileType, 71 FileID PrevFID) override; 72 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok, 73 SrcMgr::CharacteristicKind FileType) override; 74 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 75 StringRef FileName, bool IsAngled, 76 CharSourceRange FilenameRange, 77 OptionalFileEntryRef File, StringRef SearchPath, 78 StringRef RelativePath, const Module *Imported, 79 SrcMgr::CharacteristicKind FileType) override; 80 void If(SourceLocation Loc, SourceRange ConditionRange, 81 ConditionValueKind ConditionValue) override; 82 void Elif(SourceLocation Loc, SourceRange ConditionRange, 83 ConditionValueKind ConditionValue, SourceLocation IfLoc) override; 84 void WriteLineInfo(StringRef Filename, int Line, 85 SrcMgr::CharacteristicKind FileType, 86 StringRef Extra = StringRef()); 87 void WriteImplicitModuleImport(const Module *Mod); 88 void OutputContentUpTo(const MemoryBufferRef &FromFile, unsigned &WriteFrom, 89 unsigned WriteTo, StringRef EOL, int &lines, 90 bool EnsureNewline); 91 void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 92 const MemoryBufferRef &FromFile, StringRef EOL, 93 unsigned &NextToWrite, int &Lines); 94 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; 95 const Module *FindModuleAtLocation(SourceLocation Loc) const; 96 const Module *FindEnteredModule(SourceLocation Loc) const; 97 bool IsIfAtLocationTrue(SourceLocation Loc) const; 98 StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); 99 }; 100 101 } // end anonymous namespace 102 103 /// Initializes an InclusionRewriter with a \p PP source and \p OS destination. 104 InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, 105 bool ShowLineMarkers, 106 bool UseLineDirectives) 107 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), 108 ShowLineMarkers(ShowLineMarkers), UseLineDirectives(UseLineDirectives), 109 LastInclusionLocation(SourceLocation()) {} 110 111 /// Write appropriate line information as either #line directives or GNU line 112 /// markers depending on what mode we're in, including the \p Filename and 113 /// \p Line we are located at, using the specified \p EOL line separator, and 114 /// any \p Extra context specifiers in GNU line directives. 115 void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, 116 SrcMgr::CharacteristicKind FileType, 117 StringRef Extra) { 118 if (!ShowLineMarkers) 119 return; 120 if (UseLineDirectives) { 121 OS << "#line" << ' ' << Line << ' ' << '"'; 122 OS.write_escaped(Filename); 123 OS << '"'; 124 } else { 125 // Use GNU linemarkers as described here: 126 // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html 127 OS << '#' << ' ' << Line << ' ' << '"'; 128 OS.write_escaped(Filename); 129 OS << '"'; 130 if (!Extra.empty()) 131 OS << Extra; 132 if (FileType == SrcMgr::C_System) 133 // "`3' This indicates that the following text comes from a system header 134 // file, so certain warnings should be suppressed." 135 OS << " 3"; 136 else if (FileType == SrcMgr::C_ExternCSystem) 137 // as above for `3', plus "`4' This indicates that the following text 138 // should be treated as being wrapped in an implicit extern "C" block." 139 OS << " 3 4"; 140 } 141 OS << MainEOL; 142 } 143 144 void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { 145 OS << "#pragma clang module import " << Mod->getFullModuleName(true) 146 << " /* clang -frewrite-includes: implicit import */" << MainEOL; 147 } 148 149 /// FileChanged - Whenever the preprocessor enters or exits a #include file 150 /// it invokes this handler. 151 void InclusionRewriter::FileChanged(SourceLocation Loc, 152 FileChangeReason Reason, 153 SrcMgr::CharacteristicKind NewFileType, 154 FileID) { 155 if (Reason != EnterFile) 156 return; 157 if (LastInclusionLocation.isInvalid()) 158 // we didn't reach this file (eg: the main file) via an inclusion directive 159 return; 160 FileID Id = FullSourceLoc(Loc, SM).getFileID(); 161 auto P = FileIncludes.insert( 162 std::make_pair(LastInclusionLocation, IncludedFile(Id, NewFileType))); 163 (void)P; 164 assert(P.second && "Unexpected revisitation of the same include directive"); 165 LastInclusionLocation = SourceLocation(); 166 } 167 168 /// Called whenever an inclusion is skipped due to canonical header protection 169 /// macros. 170 void InclusionRewriter::FileSkipped(const FileEntryRef & /*SkippedFile*/, 171 const Token & /*FilenameTok*/, 172 SrcMgr::CharacteristicKind /*FileType*/) { 173 assert(LastInclusionLocation.isValid() && 174 "A file, that wasn't found via an inclusion directive, was skipped"); 175 LastInclusionLocation = SourceLocation(); 176 } 177 178 /// This should be called whenever the preprocessor encounters include 179 /// directives. It does not say whether the file has been included, but it 180 /// provides more information about the directive (hash location instead 181 /// of location inside the included file). It is assumed that the matching 182 /// FileChanged() or FileSkipped() is called after this (or neither is 183 /// called if this #include results in an error or does not textually include 184 /// anything). 185 void InclusionRewriter::InclusionDirective( 186 SourceLocation HashLoc, const Token & /*IncludeTok*/, 187 StringRef /*FileName*/, bool /*IsAngled*/, 188 CharSourceRange /*FilenameRange*/, OptionalFileEntryRef /*File*/, 189 StringRef /*SearchPath*/, StringRef /*RelativePath*/, 190 const Module *Imported, SrcMgr::CharacteristicKind FileType) { 191 if (Imported) { 192 auto P = ModuleIncludes.insert(std::make_pair(HashLoc, Imported)); 193 (void)P; 194 assert(P.second && "Unexpected revisitation of the same include directive"); 195 } else 196 LastInclusionLocation = HashLoc; 197 } 198 199 void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange, 200 ConditionValueKind ConditionValue) { 201 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True)); 202 (void)P; 203 assert(P.second && "Unexpected revisitation of the same if directive"); 204 } 205 206 void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange, 207 ConditionValueKind ConditionValue, 208 SourceLocation IfLoc) { 209 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True)); 210 (void)P; 211 assert(P.second && "Unexpected revisitation of the same elif directive"); 212 } 213 214 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 215 /// an inclusion directive) in the map of inclusion information, FileChanges. 216 const InclusionRewriter::IncludedFile * 217 InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc) const { 218 const auto I = FileIncludes.find(Loc); 219 if (I != FileIncludes.end()) 220 return &I->second; 221 return nullptr; 222 } 223 224 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 225 /// an inclusion directive) in the map of module inclusion information. 226 const Module * 227 InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { 228 const auto I = ModuleIncludes.find(Loc); 229 if (I != ModuleIncludes.end()) 230 return I->second; 231 return nullptr; 232 } 233 234 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 235 /// an inclusion directive) in the map of module entry information. 236 const Module * 237 InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { 238 const auto I = ModuleEntryIncludes.find(Loc); 239 if (I != ModuleEntryIncludes.end()) 240 return I->second; 241 return nullptr; 242 } 243 244 bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const { 245 const auto I = IfConditions.find(Loc); 246 if (I != IfConditions.end()) 247 return I->second; 248 return false; 249 } 250 251 void InclusionRewriter::detectMainFileEOL() { 252 std::optional<MemoryBufferRef> FromFile = 253 *SM.getBufferOrNone(SM.getMainFileID()); 254 assert(FromFile); 255 if (!FromFile) 256 return; // Should never happen, but whatever. 257 MainEOL = FromFile->getBuffer().detectEOL(); 258 } 259 260 /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 261 /// \p WriteTo - 1. 262 void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile, 263 unsigned &WriteFrom, unsigned WriteTo, 264 StringRef LocalEOL, int &Line, 265 bool EnsureNewline) { 266 if (WriteTo <= WriteFrom) 267 return; 268 if (FromFile == PredefinesBuffer) { 269 // Ignore the #defines of the predefines buffer. 270 WriteFrom = WriteTo; 271 return; 272 } 273 274 // If we would output half of a line ending, advance one character to output 275 // the whole line ending. All buffers are null terminated, so looking ahead 276 // one byte is safe. 277 if (LocalEOL.size() == 2 && 278 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] && 279 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0]) 280 WriteTo++; 281 282 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom, 283 WriteTo - WriteFrom); 284 // count lines manually, it's faster than getPresumedLoc() 285 Line += TextToWrite.count(LocalEOL); 286 287 if (MainEOL == LocalEOL) { 288 OS << TextToWrite; 289 } else { 290 // Output the file one line at a time, rewriting the line endings as we go. 291 StringRef Rest = TextToWrite; 292 while (!Rest.empty()) { 293 // Identify and output the next line excluding an EOL sequence if present. 294 size_t Idx = Rest.find(LocalEOL); 295 StringRef LineText = Rest.substr(0, Idx); 296 OS << LineText; 297 if (Idx != StringRef::npos) { 298 // An EOL sequence was present, output the EOL sequence for the 299 // main source file and skip past the local EOL sequence. 300 OS << MainEOL; 301 Idx += LocalEOL.size(); 302 } 303 // Strip the line just handled. If Idx is npos or matches the end of the 304 // text, Rest will be set to an empty string and the loop will terminate. 305 Rest = Rest.substr(Idx); 306 } 307 } 308 if (EnsureNewline && !TextToWrite.endswith(LocalEOL)) 309 OS << MainEOL; 310 311 WriteFrom = WriteTo; 312 } 313 314 /// Print characters from \p FromFile starting at \p NextToWrite up until the 315 /// inclusion directive at \p StartToken, then print out the inclusion 316 /// inclusion directive disabled by a #if directive, updating \p NextToWrite 317 /// and \p Line to track the number of source lines visited and the progress 318 /// through the \p FromFile buffer. 319 void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 320 const Token &StartToken, 321 const MemoryBufferRef &FromFile, 322 StringRef LocalEOL, 323 unsigned &NextToWrite, int &Line) { 324 OutputContentUpTo(FromFile, NextToWrite, 325 SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, 326 false); 327 Token DirectiveToken; 328 do { 329 DirectiveLex.LexFromRawLexer(DirectiveToken); 330 } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 331 if (FromFile == PredefinesBuffer) { 332 // OutputContentUpTo() would not output anything anyway. 333 return; 334 } 335 OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL; 336 OutputContentUpTo(FromFile, NextToWrite, 337 SM.getFileOffset(DirectiveToken.getLocation()) + 338 DirectiveToken.getLength(), 339 LocalEOL, Line, true); 340 OS << "#endif /* expanded by -frewrite-includes */" << MainEOL; 341 } 342 343 /// Find the next identifier in the pragma directive specified by \p RawToken. 344 StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, 345 Token &RawToken) { 346 RawLex.LexFromRawLexer(RawToken); 347 if (RawToken.is(tok::raw_identifier)) 348 PP.LookUpIdentifierInfo(RawToken); 349 if (RawToken.is(tok::identifier)) 350 return RawToken.getIdentifierInfo()->getName(); 351 return StringRef(); 352 } 353 354 /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it 355 /// and including content of included files recursively. 356 void InclusionRewriter::Process(FileID FileId, 357 SrcMgr::CharacteristicKind FileType) { 358 MemoryBufferRef FromFile; 359 { 360 auto B = SM.getBufferOrNone(FileId); 361 assert(B && "Attempting to process invalid inclusion"); 362 if (B) 363 FromFile = *B; 364 } 365 StringRef FileName = FromFile.getBufferIdentifier(); 366 Lexer RawLex(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts()); 367 RawLex.SetCommentRetentionState(false); 368 369 StringRef LocalEOL = FromFile.getBuffer().detectEOL(); 370 371 // Per the GNU docs: "1" indicates entering a new file. 372 if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) 373 WriteLineInfo(FileName, 1, FileType, ""); 374 else 375 WriteLineInfo(FileName, 1, FileType, " 1"); 376 377 if (SM.getFileIDSize(FileId) == 0) 378 return; 379 380 // The next byte to be copied from the source file, which may be non-zero if 381 // the lexer handled a BOM. 382 unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation()); 383 assert(SM.getLineNumber(FileId, NextToWrite) == 1); 384 int Line = 1; // The current input file line number. 385 386 Token RawToken; 387 RawLex.LexFromRawLexer(RawToken); 388 389 // TODO: Consider adding a switch that strips possibly unimportant content, 390 // such as comments, to reduce the size of repro files. 391 while (RawToken.isNot(tok::eof)) { 392 if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { 393 RawLex.setParsingPreprocessorDirective(true); 394 Token HashToken = RawToken; 395 RawLex.LexFromRawLexer(RawToken); 396 if (RawToken.is(tok::raw_identifier)) 397 PP.LookUpIdentifierInfo(RawToken); 398 if (RawToken.getIdentifierInfo() != nullptr) { 399 switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { 400 case tok::pp_include: 401 case tok::pp_include_next: 402 case tok::pp_import: { 403 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite, 404 Line); 405 if (FileId != PP.getPredefinesFileID()) 406 WriteLineInfo(FileName, Line - 1, FileType, ""); 407 StringRef LineInfoExtra; 408 SourceLocation Loc = HashToken.getLocation(); 409 if (const Module *Mod = FindModuleAtLocation(Loc)) 410 WriteImplicitModuleImport(Mod); 411 else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { 412 const Module *Mod = FindEnteredModule(Loc); 413 if (Mod) 414 OS << "#pragma clang module begin " 415 << Mod->getFullModuleName(true) << "\n"; 416 417 // Include and recursively process the file. 418 Process(Inc->Id, Inc->FileType); 419 420 if (Mod) 421 OS << "#pragma clang module end /*" 422 << Mod->getFullModuleName(true) << "*/\n"; 423 424 // Add line marker to indicate we're returning from an included 425 // file. 426 LineInfoExtra = " 2"; 427 } 428 // fix up lineinfo (since commented out directive changed line 429 // numbers) for inclusions that were skipped due to header guards 430 WriteLineInfo(FileName, Line, FileType, LineInfoExtra); 431 break; 432 } 433 case tok::pp_pragma: { 434 StringRef Identifier = NextIdentifierName(RawLex, RawToken); 435 if (Identifier == "clang" || Identifier == "GCC") { 436 if (NextIdentifierName(RawLex, RawToken) == "system_header") { 437 // keep the directive in, commented out 438 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 439 NextToWrite, Line); 440 // update our own type 441 FileType = SM.getFileCharacteristic(RawToken.getLocation()); 442 WriteLineInfo(FileName, Line, FileType); 443 } 444 } else if (Identifier == "once") { 445 // keep the directive in, commented out 446 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 447 NextToWrite, Line); 448 WriteLineInfo(FileName, Line, FileType); 449 } 450 break; 451 } 452 case tok::pp_if: 453 case tok::pp_elif: { 454 bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == 455 tok::pp_elif); 456 bool isTrue = IsIfAtLocationTrue(RawToken.getLocation()); 457 OutputContentUpTo(FromFile, NextToWrite, 458 SM.getFileOffset(HashToken.getLocation()), 459 LocalEOL, Line, /*EnsureNewline=*/true); 460 do { 461 RawLex.LexFromRawLexer(RawToken); 462 } while (!RawToken.is(tok::eod) && RawToken.isNot(tok::eof)); 463 // We need to disable the old condition, but that is tricky. 464 // Trying to comment it out can easily lead to comment nesting. 465 // So instead make the condition harmless by making it enclose 466 // and empty block. Moreover, put it itself inside an #if 0 block 467 // to disable it from getting evaluated (e.g. __has_include_next 468 // warns if used from the primary source file). 469 OS << "#if 0 /* disabled by -frewrite-includes */" << MainEOL; 470 if (elif) { 471 OS << "#if 0" << MainEOL; 472 } 473 OutputContentUpTo(FromFile, NextToWrite, 474 SM.getFileOffset(RawToken.getLocation()) + 475 RawToken.getLength(), 476 LocalEOL, Line, /*EnsureNewline=*/true); 477 // Close the empty block and the disabling block. 478 OS << "#endif" << MainEOL; 479 OS << "#endif /* disabled by -frewrite-includes */" << MainEOL; 480 OS << (elif ? "#elif " : "#if ") << (isTrue ? "1" : "0") 481 << " /* evaluated by -frewrite-includes */" << MainEOL; 482 WriteLineInfo(FileName, Line, FileType); 483 break; 484 } 485 case tok::pp_endif: 486 case tok::pp_else: { 487 // We surround every #include by #if 0 to comment it out, but that 488 // changes line numbers. These are fixed up right after that, but 489 // the whole #include could be inside a preprocessor conditional 490 // that is not processed. So it is necessary to fix the line 491 // numbers one the next line after each #else/#endif as well. 492 RawLex.SetKeepWhitespaceMode(true); 493 do { 494 RawLex.LexFromRawLexer(RawToken); 495 } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof)); 496 OutputContentUpTo(FromFile, NextToWrite, 497 SM.getFileOffset(RawToken.getLocation()) + 498 RawToken.getLength(), 499 LocalEOL, Line, /*EnsureNewline=*/ true); 500 WriteLineInfo(FileName, Line, FileType); 501 RawLex.SetKeepWhitespaceMode(false); 502 break; 503 } 504 default: 505 break; 506 } 507 } 508 RawLex.setParsingPreprocessorDirective(false); 509 } 510 RawLex.LexFromRawLexer(RawToken); 511 } 512 OutputContentUpTo(FromFile, NextToWrite, 513 SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, 514 Line, /*EnsureNewline=*/true); 515 } 516 517 /// InclusionRewriterInInput - Implement -frewrite-includes mode. 518 void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, 519 const PreprocessorOutputOptions &Opts) { 520 SourceManager &SM = PP.getSourceManager(); 521 InclusionRewriter *Rewrite = new InclusionRewriter( 522 PP, *OS, Opts.ShowLineMarkers, Opts.UseLineDirectives); 523 Rewrite->detectMainFileEOL(); 524 525 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Rewrite)); 526 PP.IgnorePragmas(); 527 528 // First let the preprocessor process the entire file and call callbacks. 529 // Callbacks will record which #include's were actually performed. 530 PP.EnterMainSourceFile(); 531 Token Tok; 532 // Only preprocessor directives matter here, so disable macro expansion 533 // everywhere else as an optimization. 534 // TODO: It would be even faster if the preprocessor could be switched 535 // to a mode where it would parse only preprocessor directives and comments, 536 // nothing else matters for parsing or processing. 537 PP.SetMacroExpansionOnlyInDirectives(); 538 do { 539 PP.Lex(Tok); 540 if (Tok.is(tok::annot_module_begin)) 541 Rewrite->handleModuleBegin(Tok); 542 } while (Tok.isNot(tok::eof)); 543 Rewrite->setPredefinesBuffer(SM.getBufferOrFake(PP.getPredefinesFileID())); 544 Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); 545 Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); 546 OS->flush(); 547 } 548