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