1 //===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This code rewrites include invocations into their expansions. This gives you 11 // a file with all included files merged into it. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Rewrite/Frontend/Rewriters.h" 16 #include "clang/Basic/SourceManager.h" 17 #include "clang/Frontend/PreprocessorOutputOptions.h" 18 #include "clang/Lex/HeaderSearch.h" 19 #include "clang/Lex/Pragma.h" 20 #include "clang/Lex/Preprocessor.h" 21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/Support/raw_ostream.h" 23 24 using namespace clang; 25 using namespace llvm; 26 27 namespace { 28 29 class InclusionRewriter : public PPCallbacks { 30 /// Information about which #includes were actually performed, 31 /// created by preprocessor callbacks. 32 struct IncludedFile { 33 FileID Id; 34 SrcMgr::CharacteristicKind FileType; 35 IncludedFile(FileID Id, SrcMgr::CharacteristicKind FileType) 36 : Id(Id), FileType(FileType) {} 37 }; 38 Preprocessor &PP; ///< Used to find inclusion directives. 39 SourceManager &SM; ///< Used to read and manage source files. 40 raw_ostream &OS; ///< The destination stream for rewritten contents. 41 StringRef MainEOL; ///< The line ending marker to use. 42 const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines. 43 bool ShowLineMarkers; ///< Show #line markers. 44 bool UseLineDirectives; ///< Use of line directives or line markers. 45 /// Tracks where inclusions that change the file are found. 46 std::map<unsigned, IncludedFile> FileIncludes; 47 /// Tracks where inclusions that import modules are found. 48 std::map<unsigned, const Module *> ModuleIncludes; 49 /// Tracks where inclusions that enter modules (in a module build) are found. 50 std::map<unsigned, const Module *> ModuleEntryIncludes; 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::MemoryBuffer *Buf) { 59 PredefinesBuffer = Buf; 60 } 61 void detectMainFileEOL(); 62 void handleModuleBegin(Token &Tok) { 63 assert(Tok.getKind() == tok::annot_module_begin); 64 ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(), 65 (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 FileEntry &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) override; 78 void WriteLineInfo(StringRef Filename, int Line, 79 SrcMgr::CharacteristicKind FileType, 80 StringRef Extra = StringRef()); 81 void WriteImplicitModuleImport(const Module *Mod); 82 void OutputContentUpTo(const MemoryBuffer &FromFile, 83 unsigned &WriteFrom, unsigned WriteTo, 84 StringRef EOL, int &lines, 85 bool EnsureNewline); 86 void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 87 const MemoryBuffer &FromFile, StringRef EOL, 88 unsigned &NextToWrite, int &Lines); 89 bool HandleHasInclude(FileID FileId, Lexer &RawLex, 90 const DirectoryLookup *Lookup, Token &Tok, 91 bool &FileExists); 92 const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const; 93 const Module *FindModuleAtLocation(SourceLocation Loc) const; 94 const Module *FindEnteredModule(SourceLocation Loc) const; 95 StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); 96 }; 97 98 } // end anonymous namespace 99 100 /// Initializes an InclusionRewriter with a \p PP source and \p OS destination. 101 InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, 102 bool ShowLineMarkers, 103 bool UseLineDirectives) 104 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), 105 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers), 106 UseLineDirectives(UseLineDirectives), 107 LastInclusionLocation(SourceLocation()) {} 108 109 /// Write appropriate line information as either #line directives or GNU line 110 /// markers depending on what mode we're in, including the \p Filename and 111 /// \p Line we are located at, using the specified \p EOL line separator, and 112 /// any \p Extra context specifiers in GNU line directives. 113 void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, 114 SrcMgr::CharacteristicKind FileType, 115 StringRef Extra) { 116 if (!ShowLineMarkers) 117 return; 118 if (UseLineDirectives) { 119 OS << "#line" << ' ' << Line << ' ' << '"'; 120 OS.write_escaped(Filename); 121 OS << '"'; 122 } else { 123 // Use GNU linemarkers as described here: 124 // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html 125 OS << '#' << ' ' << Line << ' ' << '"'; 126 OS.write_escaped(Filename); 127 OS << '"'; 128 if (!Extra.empty()) 129 OS << Extra; 130 if (FileType == SrcMgr::C_System) 131 // "`3' This indicates that the following text comes from a system header 132 // file, so certain warnings should be suppressed." 133 OS << " 3"; 134 else if (FileType == SrcMgr::C_ExternCSystem) 135 // as above for `3', plus "`4' This indicates that the following text 136 // should be treated as being wrapped in an implicit extern "C" block." 137 OS << " 3 4"; 138 } 139 OS << MainEOL; 140 } 141 142 void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { 143 OS << "#pragma clang module import " << Mod->getFullModuleName() 144 << " /* clang -frewrite-includes: implicit import */" << MainEOL; 145 } 146 147 /// FileChanged - Whenever the preprocessor enters or exits a #include file 148 /// it invokes this handler. 149 void InclusionRewriter::FileChanged(SourceLocation Loc, 150 FileChangeReason Reason, 151 SrcMgr::CharacteristicKind NewFileType, 152 FileID) { 153 if (Reason != EnterFile) 154 return; 155 if (LastInclusionLocation.isInvalid()) 156 // we didn't reach this file (eg: the main file) via an inclusion directive 157 return; 158 FileID Id = FullSourceLoc(Loc, SM).getFileID(); 159 auto P = FileIncludes.insert(std::make_pair( 160 LastInclusionLocation.getRawEncoding(), IncludedFile(Id, NewFileType))); 161 (void)P; 162 assert(P.second && "Unexpected revisitation of the same include directive"); 163 LastInclusionLocation = SourceLocation(); 164 } 165 166 /// Called whenever an inclusion is skipped due to canonical header protection 167 /// macros. 168 void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/, 169 const Token &/*FilenameTok*/, 170 SrcMgr::CharacteristicKind /*FileType*/) { 171 assert(LastInclusionLocation.isValid() && 172 "A file, that wasn't found via an inclusion directive, was skipped"); 173 LastInclusionLocation = SourceLocation(); 174 } 175 176 /// This should be called whenever the preprocessor encounters include 177 /// directives. It does not say whether the file has been included, but it 178 /// provides more information about the directive (hash location instead 179 /// of location inside the included file). It is assumed that the matching 180 /// FileChanged() or FileSkipped() is called after this. 181 void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, 182 const Token &/*IncludeTok*/, 183 StringRef /*FileName*/, 184 bool /*IsAngled*/, 185 CharSourceRange /*FilenameRange*/, 186 const FileEntry * /*File*/, 187 StringRef /*SearchPath*/, 188 StringRef /*RelativePath*/, 189 const Module *Imported) { 190 assert(LastInclusionLocation.isInvalid() && 191 "Another inclusion directive was found before the previous one " 192 "was processed"); 193 if (Imported) { 194 auto P = ModuleIncludes.insert( 195 std::make_pair(HashLoc.getRawEncoding(), Imported)); 196 (void)P; 197 assert(P.second && "Unexpected revisitation of the same include directive"); 198 } else 199 LastInclusionLocation = HashLoc; 200 } 201 202 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 203 /// an inclusion directive) in the map of inclusion information, FileChanges. 204 const InclusionRewriter::IncludedFile * 205 InclusionRewriter::FindIncludeAtLocation(SourceLocation Loc) const { 206 const auto I = FileIncludes.find(Loc.getRawEncoding()); 207 if (I != FileIncludes.end()) 208 return &I->second; 209 return nullptr; 210 } 211 212 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 213 /// an inclusion directive) in the map of module inclusion information. 214 const Module * 215 InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const { 216 const auto I = ModuleIncludes.find(Loc.getRawEncoding()); 217 if (I != ModuleIncludes.end()) 218 return I->second; 219 return nullptr; 220 } 221 222 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 223 /// an inclusion directive) in the map of module entry information. 224 const Module * 225 InclusionRewriter::FindEnteredModule(SourceLocation Loc) const { 226 const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding()); 227 if (I != ModuleEntryIncludes.end()) 228 return I->second; 229 return nullptr; 230 } 231 232 /// Detect the likely line ending style of \p FromFile by examining the first 233 /// newline found within it. 234 static StringRef DetectEOL(const MemoryBuffer &FromFile) { 235 // Detect what line endings the file uses, so that added content does not mix 236 // the style. We need to check for "\r\n" first because "\n\r" will match 237 // "\r\n\r\n". 238 const char *Pos = strchr(FromFile.getBufferStart(), '\n'); 239 if (!Pos) 240 return "\n"; 241 if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') 242 return "\r\n"; 243 if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') 244 return "\n\r"; 245 return "\n"; 246 } 247 248 void InclusionRewriter::detectMainFileEOL() { 249 bool Invalid; 250 const MemoryBuffer &FromFile = *SM.getBuffer(SM.getMainFileID(), &Invalid); 251 assert(!Invalid); 252 if (Invalid) 253 return; // Should never happen, but whatever. 254 MainEOL = DetectEOL(FromFile); 255 } 256 257 /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 258 /// \p WriteTo - 1. 259 void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, 260 unsigned &WriteFrom, unsigned WriteTo, 261 StringRef LocalEOL, int &Line, 262 bool EnsureNewline) { 263 if (WriteTo <= WriteFrom) 264 return; 265 if (&FromFile == PredefinesBuffer) { 266 // Ignore the #defines of the predefines buffer. 267 WriteFrom = WriteTo; 268 return; 269 } 270 271 // If we would output half of a line ending, advance one character to output 272 // the whole line ending. All buffers are null terminated, so looking ahead 273 // one byte is safe. 274 if (LocalEOL.size() == 2 && 275 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] && 276 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0]) 277 WriteTo++; 278 279 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom, 280 WriteTo - WriteFrom); 281 282 if (MainEOL == LocalEOL) { 283 OS << TextToWrite; 284 // count lines manually, it's faster than getPresumedLoc() 285 Line += TextToWrite.count(LocalEOL); 286 if (EnsureNewline && !TextToWrite.endswith(LocalEOL)) 287 OS << MainEOL; 288 } else { 289 // Output the file one line at a time, rewriting the line endings as we go. 290 StringRef Rest = TextToWrite; 291 while (!Rest.empty()) { 292 StringRef LineText; 293 std::tie(LineText, Rest) = Rest.split(LocalEOL); 294 OS << LineText; 295 Line++; 296 if (!Rest.empty()) 297 OS << MainEOL; 298 } 299 if (TextToWrite.endswith(LocalEOL) || EnsureNewline) 300 OS << MainEOL; 301 } 302 WriteFrom = WriteTo; 303 } 304 305 /// Print characters from \p FromFile starting at \p NextToWrite up until the 306 /// inclusion directive at \p StartToken, then print out the inclusion 307 /// inclusion directive disabled by a #if directive, updating \p NextToWrite 308 /// and \p Line to track the number of source lines visited and the progress 309 /// through the \p FromFile buffer. 310 void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 311 const Token &StartToken, 312 const MemoryBuffer &FromFile, 313 StringRef LocalEOL, 314 unsigned &NextToWrite, int &Line) { 315 OutputContentUpTo(FromFile, NextToWrite, 316 SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, 317 false); 318 Token DirectiveToken; 319 do { 320 DirectiveLex.LexFromRawLexer(DirectiveToken); 321 } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 322 if (&FromFile == PredefinesBuffer) { 323 // OutputContentUpTo() would not output anything anyway. 324 return; 325 } 326 OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL; 327 OutputContentUpTo(FromFile, NextToWrite, 328 SM.getFileOffset(DirectiveToken.getLocation()) + 329 DirectiveToken.getLength(), 330 LocalEOL, Line, true); 331 OS << "#endif /* expanded by -frewrite-includes */" << MainEOL; 332 } 333 334 /// Find the next identifier in the pragma directive specified by \p RawToken. 335 StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, 336 Token &RawToken) { 337 RawLex.LexFromRawLexer(RawToken); 338 if (RawToken.is(tok::raw_identifier)) 339 PP.LookUpIdentifierInfo(RawToken); 340 if (RawToken.is(tok::identifier)) 341 return RawToken.getIdentifierInfo()->getName(); 342 return StringRef(); 343 } 344 345 // Expand __has_include and __has_include_next if possible. If there's no 346 // definitive answer return false. 347 bool InclusionRewriter::HandleHasInclude( 348 FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, 349 bool &FileExists) { 350 // Lex the opening paren. 351 RawLex.LexFromRawLexer(Tok); 352 if (Tok.isNot(tok::l_paren)) 353 return false; 354 355 RawLex.LexFromRawLexer(Tok); 356 357 SmallString<128> FilenameBuffer; 358 StringRef Filename; 359 // Since the raw lexer doesn't give us angle_literals we have to parse them 360 // ourselves. 361 // FIXME: What to do if the file name is a macro? 362 if (Tok.is(tok::less)) { 363 RawLex.LexFromRawLexer(Tok); 364 365 FilenameBuffer += '<'; 366 do { 367 if (Tok.is(tok::eod)) // Sanity check. 368 return false; 369 370 if (Tok.is(tok::raw_identifier)) 371 PP.LookUpIdentifierInfo(Tok); 372 373 // Get the string piece. 374 SmallVector<char, 128> TmpBuffer; 375 bool Invalid = false; 376 StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); 377 if (Invalid) 378 return false; 379 380 FilenameBuffer += TmpName; 381 382 RawLex.LexFromRawLexer(Tok); 383 } while (Tok.isNot(tok::greater)); 384 385 FilenameBuffer += '>'; 386 Filename = FilenameBuffer; 387 } else { 388 if (Tok.isNot(tok::string_literal)) 389 return false; 390 391 bool Invalid = false; 392 Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); 393 if (Invalid) 394 return false; 395 } 396 397 // Lex the closing paren. 398 RawLex.LexFromRawLexer(Tok); 399 if (Tok.isNot(tok::r_paren)) 400 return false; 401 402 // Now ask HeaderInfo if it knows about the header. 403 // FIXME: Subframeworks aren't handled here. Do we care? 404 bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); 405 const DirectoryLookup *CurDir; 406 const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId); 407 SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1> 408 Includers; 409 Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir())); 410 // FIXME: Why don't we call PP.LookupFile here? 411 const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( 412 Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr, 413 nullptr, nullptr, nullptr, nullptr); 414 415 FileExists = File != nullptr; 416 return true; 417 } 418 419 /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it 420 /// and including content of included files recursively. 421 void InclusionRewriter::Process(FileID FileId, 422 SrcMgr::CharacteristicKind FileType) { 423 bool Invalid; 424 const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); 425 assert(!Invalid && "Attempting to process invalid inclusion"); 426 StringRef FileName = FromFile.getBufferIdentifier(); 427 Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); 428 RawLex.SetCommentRetentionState(false); 429 430 StringRef LocalEOL = DetectEOL(FromFile); 431 432 // Per the GNU docs: "1" indicates entering a new file. 433 if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) 434 WriteLineInfo(FileName, 1, FileType, ""); 435 else 436 WriteLineInfo(FileName, 1, FileType, " 1"); 437 438 if (SM.getFileIDSize(FileId) == 0) 439 return; 440 441 // The next byte to be copied from the source file, which may be non-zero if 442 // the lexer handled a BOM. 443 unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation()); 444 assert(SM.getLineNumber(FileId, NextToWrite) == 1); 445 int Line = 1; // The current input file line number. 446 447 Token RawToken; 448 RawLex.LexFromRawLexer(RawToken); 449 450 // TODO: Consider adding a switch that strips possibly unimportant content, 451 // such as comments, to reduce the size of repro files. 452 while (RawToken.isNot(tok::eof)) { 453 if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { 454 RawLex.setParsingPreprocessorDirective(true); 455 Token HashToken = RawToken; 456 RawLex.LexFromRawLexer(RawToken); 457 if (RawToken.is(tok::raw_identifier)) 458 PP.LookUpIdentifierInfo(RawToken); 459 if (RawToken.getIdentifierInfo() != nullptr) { 460 switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { 461 case tok::pp_include: 462 case tok::pp_include_next: 463 case tok::pp_import: { 464 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite, 465 Line); 466 if (FileId != PP.getPredefinesFileID()) 467 WriteLineInfo(FileName, Line - 1, FileType, ""); 468 StringRef LineInfoExtra; 469 SourceLocation Loc = HashToken.getLocation(); 470 if (const Module *Mod = FindModuleAtLocation(Loc)) 471 WriteImplicitModuleImport(Mod); 472 else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { 473 const Module *Mod = FindEnteredModule(Loc); 474 if (Mod) 475 OS << "#pragma clang module begin " << Mod->getFullModuleName() 476 << "\n"; 477 478 // Include and recursively process the file. 479 Process(Inc->Id, Inc->FileType); 480 481 if (Mod) 482 OS << "#pragma clang module end /*" << Mod->getFullModuleName() 483 << "*/\n"; 484 485 // Add line marker to indicate we're returning from an included 486 // file. 487 LineInfoExtra = " 2"; 488 } 489 // fix up lineinfo (since commented out directive changed line 490 // numbers) for inclusions that were skipped due to header guards 491 WriteLineInfo(FileName, Line, FileType, LineInfoExtra); 492 break; 493 } 494 case tok::pp_pragma: { 495 StringRef Identifier = NextIdentifierName(RawLex, RawToken); 496 if (Identifier == "clang" || Identifier == "GCC") { 497 if (NextIdentifierName(RawLex, RawToken) == "system_header") { 498 // keep the directive in, commented out 499 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 500 NextToWrite, Line); 501 // update our own type 502 FileType = SM.getFileCharacteristic(RawToken.getLocation()); 503 WriteLineInfo(FileName, Line, FileType); 504 } 505 } else if (Identifier == "once") { 506 // keep the directive in, commented out 507 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 508 NextToWrite, Line); 509 WriteLineInfo(FileName, Line, FileType); 510 } 511 break; 512 } 513 case tok::pp_if: 514 case tok::pp_elif: { 515 bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == 516 tok::pp_elif); 517 // Rewrite special builtin macros to avoid pulling in host details. 518 do { 519 // Walk over the directive. 520 RawLex.LexFromRawLexer(RawToken); 521 if (RawToken.is(tok::raw_identifier)) 522 PP.LookUpIdentifierInfo(RawToken); 523 524 if (RawToken.is(tok::identifier)) { 525 bool HasFile; 526 SourceLocation Loc = RawToken.getLocation(); 527 528 // Rewrite __has_include(x) 529 if (RawToken.getIdentifierInfo()->isStr("__has_include")) { 530 if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken, 531 HasFile)) 532 continue; 533 // Rewrite __has_include_next(x) 534 } else if (RawToken.getIdentifierInfo()->isStr( 535 "__has_include_next")) { 536 const DirectoryLookup *Lookup = PP.GetCurDirLookup(); 537 if (Lookup) 538 ++Lookup; 539 540 if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken, 541 HasFile)) 542 continue; 543 } else { 544 continue; 545 } 546 // Replace the macro with (0) or (1), followed by the commented 547 // out macro for reference. 548 OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), 549 LocalEOL, Line, false); 550 OS << '(' << (int) HasFile << ")/*"; 551 OutputContentUpTo(FromFile, NextToWrite, 552 SM.getFileOffset(RawToken.getLocation()) + 553 RawToken.getLength(), 554 LocalEOL, Line, false); 555 OS << "*/"; 556 } 557 } while (RawToken.isNot(tok::eod)); 558 if (elif) { 559 OutputContentUpTo(FromFile, NextToWrite, 560 SM.getFileOffset(RawToken.getLocation()) + 561 RawToken.getLength(), 562 LocalEOL, Line, /*EnsureNewline=*/ true); 563 WriteLineInfo(FileName, Line, FileType); 564 } 565 break; 566 } 567 case tok::pp_endif: 568 case tok::pp_else: { 569 // We surround every #include by #if 0 to comment it out, but that 570 // changes line numbers. These are fixed up right after that, but 571 // the whole #include could be inside a preprocessor conditional 572 // that is not processed. So it is necessary to fix the line 573 // numbers one the next line after each #else/#endif as well. 574 RawLex.SetKeepWhitespaceMode(true); 575 do { 576 RawLex.LexFromRawLexer(RawToken); 577 } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof)); 578 OutputContentUpTo(FromFile, NextToWrite, 579 SM.getFileOffset(RawToken.getLocation()) + 580 RawToken.getLength(), 581 LocalEOL, Line, /*EnsureNewline=*/ true); 582 WriteLineInfo(FileName, Line, FileType); 583 RawLex.SetKeepWhitespaceMode(false); 584 } 585 default: 586 break; 587 } 588 } 589 RawLex.setParsingPreprocessorDirective(false); 590 } 591 RawLex.LexFromRawLexer(RawToken); 592 } 593 OutputContentUpTo(FromFile, NextToWrite, 594 SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, 595 Line, /*EnsureNewline=*/true); 596 } 597 598 /// InclusionRewriterInInput - Implement -frewrite-includes mode. 599 void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, 600 const PreprocessorOutputOptions &Opts) { 601 SourceManager &SM = PP.getSourceManager(); 602 InclusionRewriter *Rewrite = new InclusionRewriter( 603 PP, *OS, Opts.ShowLineMarkers, Opts.UseLineDirectives); 604 Rewrite->detectMainFileEOL(); 605 606 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Rewrite)); 607 PP.IgnorePragmas(); 608 609 // First let the preprocessor process the entire file and call callbacks. 610 // Callbacks will record which #include's were actually performed. 611 PP.EnterMainSourceFile(); 612 Token Tok; 613 // Only preprocessor directives matter here, so disable macro expansion 614 // everywhere else as an optimization. 615 // TODO: It would be even faster if the preprocessor could be switched 616 // to a mode where it would parse only preprocessor directives and comments, 617 // nothing else matters for parsing or processing. 618 PP.SetMacroExpansionOnlyInDirectives(); 619 do { 620 PP.Lex(Tok); 621 if (Tok.is(tok::annot_module_begin)) 622 Rewrite->handleModuleBegin(Tok); 623 } while (Tok.isNot(tok::eof)); 624 Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); 625 Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); 626 Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); 627 OS->flush(); 628 } 629