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