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