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 *SuggestedModule, 79 bool ModuleImported, 80 SrcMgr::CharacteristicKind FileType) override; 81 void If(SourceLocation Loc, SourceRange ConditionRange, 82 ConditionValueKind ConditionValue) override; 83 void Elif(SourceLocation Loc, SourceRange ConditionRange, 84 ConditionValueKind ConditionValue, SourceLocation IfLoc) override; 85 void WriteLineInfo(StringRef Filename, int Line, 86 SrcMgr::CharacteristicKind FileType, 87 StringRef Extra = StringRef()); 88 void WriteImplicitModuleImport(const Module *Mod); 89 void OutputContentUpTo(const MemoryBufferRef &FromFile, unsigned &WriteFrom, 90 unsigned WriteTo, StringRef EOL, int &lines, 91 bool EnsureNewline); 92 void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 93 const MemoryBufferRef &FromFile, StringRef EOL, 94 unsigned &NextToWrite, int &Lines, 95 const IncludedFile *Inc = nullptr); 96 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; 97 StringRef getIncludedFileName(const IncludedFile *Inc) 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, IncludedFile(Id, NewFileType))); 166 (void)P; 167 assert(P.second && "Unexpected revisitation of the same include directive"); 168 LastInclusionLocation = SourceLocation(); 169 } 170 171 /// Called whenever an inclusion is skipped due to canonical header protection 172 /// macros. 173 void InclusionRewriter::FileSkipped(const FileEntryRef & /*SkippedFile*/, 174 const Token & /*FilenameTok*/, 175 SrcMgr::CharacteristicKind /*FileType*/) { 176 assert(LastInclusionLocation.isValid() && 177 "A file, that wasn't found via an inclusion directive, was skipped"); 178 LastInclusionLocation = SourceLocation(); 179 } 180 181 /// This should be called whenever the preprocessor encounters include 182 /// directives. It does not say whether the file has been included, but it 183 /// provides more information about the directive (hash location instead 184 /// of location inside the included file). It is assumed that the matching 185 /// FileChanged() or FileSkipped() is called after this (or neither is 186 /// called if this #include results in an error or does not textually include 187 /// anything). 188 void InclusionRewriter::InclusionDirective( 189 SourceLocation HashLoc, const Token & /*IncludeTok*/, 190 StringRef /*FileName*/, bool /*IsAngled*/, 191 CharSourceRange /*FilenameRange*/, OptionalFileEntryRef /*File*/, 192 StringRef /*SearchPath*/, StringRef /*RelativePath*/, 193 const Module *SuggestedModule, bool ModuleImported, 194 SrcMgr::CharacteristicKind FileType) { 195 if (ModuleImported) { 196 auto P = ModuleIncludes.insert(std::make_pair(HashLoc, SuggestedModule)); 197 (void)P; 198 assert(P.second && "Unexpected revisitation of the same include directive"); 199 } else 200 LastInclusionLocation = HashLoc; 201 } 202 203 void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange, 204 ConditionValueKind ConditionValue) { 205 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True)); 206 (void)P; 207 assert(P.second && "Unexpected revisitation of the same if directive"); 208 } 209 210 void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange, 211 ConditionValueKind ConditionValue, 212 SourceLocation IfLoc) { 213 auto P = IfConditions.insert(std::make_pair(Loc, ConditionValue == CVK_True)); 214 (void)P; 215 assert(P.second && "Unexpected revisitation of the same elif directive"); 216 } 217 218 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 219 /// an inclusion directive) in the map of inclusion information, FileChanges. 220 const InclusionRewriter::IncludedFile * 221 InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc) const { 222 const auto I = FileIncludes.find(Loc); 223 if (I != FileIncludes.end()) 224 return &I->second; 225 return nullptr; 226 } 227 228 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 229 /// an inclusion directive) in the map of module inclusion information. 230 const Module * 231 InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { 232 const auto I = ModuleIncludes.find(Loc); 233 if (I != ModuleIncludes.end()) 234 return I->second; 235 return nullptr; 236 } 237 238 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 239 /// an inclusion directive) in the map of module entry information. 240 const Module * 241 InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { 242 const auto I = ModuleEntryIncludes.find(Loc); 243 if (I != ModuleEntryIncludes.end()) 244 return I->second; 245 return nullptr; 246 } 247 248 bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const { 249 const auto I = IfConditions.find(Loc); 250 if (I != IfConditions.end()) 251 return I->second; 252 return false; 253 } 254 255 void InclusionRewriter::detectMainFileEOL() { 256 std::optional<MemoryBufferRef> FromFile = 257 *SM.getBufferOrNone(SM.getMainFileID()); 258 assert(FromFile); 259 if (!FromFile) 260 return; // Should never happen, but whatever. 261 MainEOL = FromFile->getBuffer().detectEOL(); 262 } 263 264 /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 265 /// \p WriteTo - 1. 266 void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile, 267 unsigned &WriteFrom, unsigned WriteTo, 268 StringRef LocalEOL, int &Line, 269 bool EnsureNewline) { 270 if (WriteTo <= WriteFrom) 271 return; 272 if (FromFile == PredefinesBuffer) { 273 // Ignore the #defines of the predefines buffer. 274 WriteFrom = WriteTo; 275 return; 276 } 277 278 // If we would output half of a line ending, advance one character to output 279 // the whole line ending. All buffers are null terminated, so looking ahead 280 // one byte is safe. 281 if (LocalEOL.size() == 2 && 282 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] && 283 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0]) 284 WriteTo++; 285 286 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom, 287 WriteTo - WriteFrom); 288 // count lines manually, it's faster than getPresumedLoc() 289 Line += TextToWrite.count(LocalEOL); 290 291 if (MainEOL == LocalEOL) { 292 OS << TextToWrite; 293 } else { 294 // Output the file one line at a time, rewriting the line endings as we go. 295 StringRef Rest = TextToWrite; 296 while (!Rest.empty()) { 297 // Identify and output the next line excluding an EOL sequence if present. 298 size_t Idx = Rest.find(LocalEOL); 299 StringRef LineText = Rest.substr(0, Idx); 300 OS << LineText; 301 if (Idx != StringRef::npos) { 302 // An EOL sequence was present, output the EOL sequence for the 303 // main source file and skip past the local EOL sequence. 304 OS << MainEOL; 305 Idx += LocalEOL.size(); 306 } 307 // Strip the line just handled. If Idx is npos or matches the end of the 308 // text, Rest will be set to an empty string and the loop will terminate. 309 Rest = Rest.substr(Idx); 310 } 311 } 312 if (EnsureNewline && !TextToWrite.ends_with(LocalEOL)) 313 OS << MainEOL; 314 315 WriteFrom = WriteTo; 316 } 317 318 StringRef 319 InclusionRewriter::getIncludedFileName(const IncludedFile *Inc) const { 320 if (Inc) { 321 auto B = SM.getBufferOrNone(Inc->Id); 322 assert(B && "Attempting to process invalid inclusion"); 323 if (B) 324 return llvm::sys::path::filename(B->getBufferIdentifier()); 325 } 326 return StringRef(); 327 } 328 329 /// Print characters from \p FromFile starting at \p NextToWrite up until the 330 /// inclusion directive at \p StartToken, then print out the inclusion 331 /// inclusion directive disabled by a #if directive, updating \p NextToWrite 332 /// and \p Line to track the number of source lines visited and the progress 333 /// through the \p FromFile buffer. 334 void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 335 const Token &StartToken, 336 const MemoryBufferRef &FromFile, 337 StringRef LocalEOL, 338 unsigned &NextToWrite, int &Line, 339 const IncludedFile *Inc) { 340 OutputContentUpTo(FromFile, NextToWrite, 341 SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, 342 false); 343 Token DirectiveToken; 344 do { 345 DirectiveLex.LexFromRawLexer(DirectiveToken); 346 } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 347 if (FromFile == PredefinesBuffer) { 348 // OutputContentUpTo() would not output anything anyway. 349 return; 350 } 351 if (Inc) { 352 OS << "#if defined(__CLANG_REWRITTEN_INCLUDES) "; 353 if (isSystem(Inc->FileType)) 354 OS << "|| defined(__CLANG_REWRITTEN_SYSTEM_INCLUDES) "; 355 OS << "/* " << getIncludedFileName(Inc); 356 } else { 357 OS << "#if 0 /*"; 358 } 359 OS << " expanded by -frewrite-includes */" << MainEOL; 360 OutputContentUpTo(FromFile, NextToWrite, 361 SM.getFileOffset(DirectiveToken.getLocation()) + 362 DirectiveToken.getLength(), 363 LocalEOL, Line, true); 364 OS << (Inc ? "#else /* " : "#endif /*") << getIncludedFileName(Inc) 365 << " expanded by -frewrite-includes */" << MainEOL; 366 } 367 368 /// Find the next identifier in the pragma directive specified by \p RawToken. 369 StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, 370 Token &RawToken) { 371 RawLex.LexFromRawLexer(RawToken); 372 if (RawToken.is(tok::raw_identifier)) 373 PP.LookUpIdentifierInfo(RawToken); 374 if (RawToken.is(tok::identifier)) 375 return RawToken.getIdentifierInfo()->getName(); 376 return StringRef(); 377 } 378 379 /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it 380 /// and including content of included files recursively. 381 void InclusionRewriter::Process(FileID FileId, 382 SrcMgr::CharacteristicKind FileType) { 383 MemoryBufferRef FromFile; 384 { 385 auto B = SM.getBufferOrNone(FileId); 386 assert(B && "Attempting to process invalid inclusion"); 387 if (B) 388 FromFile = *B; 389 } 390 StringRef FileName = FromFile.getBufferIdentifier(); 391 Lexer RawLex(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts()); 392 RawLex.SetCommentRetentionState(false); 393 394 StringRef LocalEOL = FromFile.getBuffer().detectEOL(); 395 396 // Per the GNU docs: "1" indicates entering a new file. 397 if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) 398 WriteLineInfo(FileName, 1, FileType, ""); 399 else 400 WriteLineInfo(FileName, 1, FileType, " 1"); 401 402 if (SM.getFileIDSize(FileId) == 0) 403 return; 404 405 // The next byte to be copied from the source file, which may be non-zero if 406 // the lexer handled a BOM. 407 unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation()); 408 assert(SM.getLineNumber(FileId, NextToWrite) == 1); 409 int Line = 1; // The current input file line number. 410 411 Token RawToken; 412 RawLex.LexFromRawLexer(RawToken); 413 414 // TODO: Consider adding a switch that strips possibly unimportant content, 415 // such as comments, to reduce the size of repro files. 416 while (RawToken.isNot(tok::eof)) { 417 if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { 418 RawLex.setParsingPreprocessorDirective(true); 419 Token HashToken = RawToken; 420 RawLex.LexFromRawLexer(RawToken); 421 if (RawToken.is(tok::raw_identifier)) 422 PP.LookUpIdentifierInfo(RawToken); 423 if (RawToken.getIdentifierInfo() != nullptr) { 424 switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { 425 case tok::pp_include: 426 case tok::pp_include_next: 427 case tok::pp_import: { 428 SourceLocation Loc = HashToken.getLocation(); 429 const IncludedFile *Inc = FindIncludeAtLocation(Loc); 430 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 431 NextToWrite, Line, Inc); 432 if (FileId != PP.getPredefinesFileID()) 433 WriteLineInfo(FileName, Line - 1, FileType, ""); 434 StringRef LineInfoExtra; 435 if (const Module *Mod = FindModuleAtLocation(Loc)) 436 WriteImplicitModuleImport(Mod); 437 else if (Inc) { 438 const Module *Mod = FindEnteredModule(Loc); 439 if (Mod) 440 OS << "#pragma clang module begin " 441 << Mod->getFullModuleName(true) << "\n"; 442 443 // Include and recursively process the file. 444 Process(Inc->Id, Inc->FileType); 445 446 if (Mod) 447 OS << "#pragma clang module end /*" 448 << Mod->getFullModuleName(true) << "*/\n"; 449 // There's no #include, therefore no #if, for -include files. 450 if (FromFile != PredefinesBuffer) { 451 OS << "#endif /* " << getIncludedFileName(Inc) 452 << " expanded by -frewrite-includes */" << LocalEOL; 453 } 454 455 // Add line marker to indicate we're returning from an included 456 // file. 457 LineInfoExtra = " 2"; 458 } 459 // fix up lineinfo (since commented out directive changed line 460 // numbers) for inclusions that were skipped due to header guards 461 WriteLineInfo(FileName, Line, FileType, LineInfoExtra); 462 break; 463 } 464 case tok::pp_pragma: { 465 StringRef Identifier = NextIdentifierName(RawLex, RawToken); 466 if (Identifier == "clang" || Identifier == "GCC") { 467 if (NextIdentifierName(RawLex, RawToken) == "system_header") { 468 // keep the directive in, commented out 469 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 470 NextToWrite, Line); 471 // update our own type 472 FileType = SM.getFileCharacteristic(RawToken.getLocation()); 473 WriteLineInfo(FileName, Line, FileType); 474 } 475 } else if (Identifier == "once") { 476 // keep the directive in, commented out 477 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 478 NextToWrite, Line); 479 WriteLineInfo(FileName, Line, FileType); 480 } 481 break; 482 } 483 case tok::pp_if: 484 case tok::pp_elif: { 485 bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == 486 tok::pp_elif); 487 bool isTrue = IsIfAtLocationTrue(RawToken.getLocation()); 488 OutputContentUpTo(FromFile, NextToWrite, 489 SM.getFileOffset(HashToken.getLocation()), 490 LocalEOL, Line, /*EnsureNewline=*/true); 491 do { 492 RawLex.LexFromRawLexer(RawToken); 493 } while (!RawToken.is(tok::eod) && RawToken.isNot(tok::eof)); 494 // We need to disable the old condition, but that is tricky. 495 // Trying to comment it out can easily lead to comment nesting. 496 // So instead make the condition harmless by making it enclose 497 // and empty block. Moreover, put it itself inside an #if 0 block 498 // to disable it from getting evaluated (e.g. __has_include_next 499 // warns if used from the primary source file). 500 OS << "#if 0 /* disabled by -frewrite-includes */" << MainEOL; 501 if (elif) { 502 OS << "#if 0" << MainEOL; 503 } 504 OutputContentUpTo(FromFile, NextToWrite, 505 SM.getFileOffset(RawToken.getLocation()) + 506 RawToken.getLength(), 507 LocalEOL, Line, /*EnsureNewline=*/true); 508 // Close the empty block and the disabling block. 509 OS << "#endif" << MainEOL; 510 OS << "#endif /* disabled by -frewrite-includes */" << MainEOL; 511 OS << (elif ? "#elif " : "#if ") << (isTrue ? "1" : "0") 512 << " /* evaluated by -frewrite-includes */" << MainEOL; 513 WriteLineInfo(FileName, Line, FileType); 514 break; 515 } 516 case tok::pp_endif: 517 case tok::pp_else: { 518 // We surround every #include by #if 0 to comment it out, but that 519 // changes line numbers. These are fixed up right after that, but 520 // the whole #include could be inside a preprocessor conditional 521 // that is not processed. So it is necessary to fix the line 522 // numbers one the next line after each #else/#endif as well. 523 RawLex.SetKeepWhitespaceMode(true); 524 do { 525 RawLex.LexFromRawLexer(RawToken); 526 } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof)); 527 OutputContentUpTo(FromFile, NextToWrite, 528 SM.getFileOffset(RawToken.getLocation()) + 529 RawToken.getLength(), 530 LocalEOL, Line, /*EnsureNewline=*/ true); 531 WriteLineInfo(FileName, Line, FileType); 532 RawLex.SetKeepWhitespaceMode(false); 533 break; 534 } 535 default: 536 break; 537 } 538 } 539 RawLex.setParsingPreprocessorDirective(false); 540 } 541 RawLex.LexFromRawLexer(RawToken); 542 } 543 OutputContentUpTo(FromFile, NextToWrite, 544 SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, 545 Line, /*EnsureNewline=*/true); 546 } 547 548 /// InclusionRewriterInInput - Implement -frewrite-includes mode. 549 void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, 550 const PreprocessorOutputOptions &Opts) { 551 SourceManager &SM = PP.getSourceManager(); 552 InclusionRewriter *Rewrite = new InclusionRewriter( 553 PP, *OS, Opts.ShowLineMarkers, Opts.UseLineDirectives); 554 Rewrite->detectMainFileEOL(); 555 556 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Rewrite)); 557 PP.IgnorePragmas(); 558 559 // First let the preprocessor process the entire file and call callbacks. 560 // Callbacks will record which #include's were actually performed. 561 PP.EnterMainSourceFile(); 562 Token Tok; 563 // Only preprocessor directives matter here, so disable macro expansion 564 // everywhere else as an optimization. 565 // TODO: It would be even faster if the preprocessor could be switched 566 // to a mode where it would parse only preprocessor directives and comments, 567 // nothing else matters for parsing or processing. 568 PP.SetMacroExpansionOnlyInDirectives(); 569 do { 570 PP.Lex(Tok); 571 if (Tok.is(tok::annot_module_begin)) 572 Rewrite->handleModuleBegin(Tok); 573 } while (Tok.isNot(tok::eof)); 574 Rewrite->setPredefinesBuffer(SM.getBufferOrFake(PP.getPredefinesFileID())); 575 Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); 576 Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); 577 OS->flush(); 578 } 579