clang API Documentation
00001 //===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This code rewrites include invocations into their expansions. This gives you 00011 // a file with all included files merged into it. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "clang/Rewrite/Frontend/Rewriters.h" 00016 #include "clang/Basic/SourceManager.h" 00017 #include "clang/Frontend/PreprocessorOutputOptions.h" 00018 #include "clang/Lex/HeaderSearch.h" 00019 #include "clang/Lex/Pragma.h" 00020 #include "clang/Lex/Preprocessor.h" 00021 #include "llvm/ADT/SmallString.h" 00022 #include "llvm/Support/raw_ostream.h" 00023 00024 using namespace clang; 00025 using namespace llvm; 00026 00027 namespace { 00028 00029 class InclusionRewriter : public PPCallbacks { 00030 /// Information about which #includes were actually performed, 00031 /// created by preprocessor callbacks. 00032 struct FileChange { 00033 const Module *Mod; 00034 SourceLocation From; 00035 FileID Id; 00036 SrcMgr::CharacteristicKind FileType; 00037 FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) { 00038 } 00039 }; 00040 Preprocessor &PP; ///< Used to find inclusion directives. 00041 SourceManager &SM; ///< Used to read and manage source files. 00042 raw_ostream &OS; ///< The destination stream for rewritten contents. 00043 StringRef MainEOL; ///< The line ending marker to use. 00044 const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines. 00045 bool ShowLineMarkers; ///< Show #line markers. 00046 bool UseLineDirective; ///< Use of line directives or line markers. 00047 typedef std::map<unsigned, FileChange> FileChangeMap; 00048 FileChangeMap FileChanges; ///< Tracks which files were included where. 00049 /// Used transitively for building up the FileChanges mapping over the 00050 /// various \c PPCallbacks callbacks. 00051 FileChangeMap::iterator LastInsertedFileChange; 00052 public: 00053 InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers); 00054 bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); 00055 void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { 00056 PredefinesBuffer = Buf; 00057 } 00058 void detectMainFileEOL(); 00059 private: 00060 void FileChanged(SourceLocation Loc, FileChangeReason Reason, 00061 SrcMgr::CharacteristicKind FileType, 00062 FileID PrevFID) override; 00063 void FileSkipped(const FileEntry &ParentFile, const Token &FilenameTok, 00064 SrcMgr::CharacteristicKind FileType) override; 00065 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, 00066 StringRef FileName, bool IsAngled, 00067 CharSourceRange FilenameRange, const FileEntry *File, 00068 StringRef SearchPath, StringRef RelativePath, 00069 const Module *Imported) override; 00070 void WriteLineInfo(const char *Filename, int Line, 00071 SrcMgr::CharacteristicKind FileType, 00072 StringRef Extra = StringRef()); 00073 void WriteImplicitModuleImport(const Module *Mod); 00074 void OutputContentUpTo(const MemoryBuffer &FromFile, 00075 unsigned &WriteFrom, unsigned WriteTo, 00076 StringRef EOL, int &lines, 00077 bool EnsureNewline); 00078 void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, 00079 const MemoryBuffer &FromFile, StringRef EOL, 00080 unsigned &NextToWrite, int &Lines); 00081 bool HandleHasInclude(FileID FileId, Lexer &RawLex, 00082 const DirectoryLookup *Lookup, Token &Tok, 00083 bool &FileExists); 00084 const FileChange *FindFileChangeLocation(SourceLocation Loc) const; 00085 StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); 00086 }; 00087 00088 } // end anonymous namespace 00089 00090 /// Initializes an InclusionRewriter with a \p PP source and \p OS destination. 00091 InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, 00092 bool ShowLineMarkers) 00093 : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), 00094 PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers), 00095 LastInsertedFileChange(FileChanges.end()) { 00096 // If we're in microsoft mode, use normal #line instead of line markers. 00097 UseLineDirective = PP.getLangOpts().MicrosoftExt; 00098 } 00099 00100 /// Write appropriate line information as either #line directives or GNU line 00101 /// markers depending on what mode we're in, including the \p Filename and 00102 /// \p Line we are located at, using the specified \p EOL line separator, and 00103 /// any \p Extra context specifiers in GNU line directives. 00104 void InclusionRewriter::WriteLineInfo(const char *Filename, int Line, 00105 SrcMgr::CharacteristicKind FileType, 00106 StringRef Extra) { 00107 if (!ShowLineMarkers) 00108 return; 00109 if (UseLineDirective) { 00110 OS << "#line" << ' ' << Line << ' ' << '"'; 00111 OS.write_escaped(Filename); 00112 OS << '"'; 00113 } else { 00114 // Use GNU linemarkers as described here: 00115 // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html 00116 OS << '#' << ' ' << Line << ' ' << '"'; 00117 OS.write_escaped(Filename); 00118 OS << '"'; 00119 if (!Extra.empty()) 00120 OS << Extra; 00121 if (FileType == SrcMgr::C_System) 00122 // "`3' This indicates that the following text comes from a system header 00123 // file, so certain warnings should be suppressed." 00124 OS << " 3"; 00125 else if (FileType == SrcMgr::C_ExternCSystem) 00126 // as above for `3', plus "`4' This indicates that the following text 00127 // should be treated as being wrapped in an implicit extern "C" block." 00128 OS << " 3 4"; 00129 } 00130 OS << MainEOL; 00131 } 00132 00133 void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { 00134 OS << "@import " << Mod->getFullModuleName() << ";" 00135 << " /* clang -frewrite-includes: implicit import */" << MainEOL; 00136 } 00137 00138 /// FileChanged - Whenever the preprocessor enters or exits a #include file 00139 /// it invokes this handler. 00140 void InclusionRewriter::FileChanged(SourceLocation Loc, 00141 FileChangeReason Reason, 00142 SrcMgr::CharacteristicKind NewFileType, 00143 FileID) { 00144 if (Reason != EnterFile) 00145 return; 00146 if (LastInsertedFileChange == FileChanges.end()) 00147 // we didn't reach this file (eg: the main file) via an inclusion directive 00148 return; 00149 LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID(); 00150 LastInsertedFileChange->second.FileType = NewFileType; 00151 LastInsertedFileChange = FileChanges.end(); 00152 } 00153 00154 /// Called whenever an inclusion is skipped due to canonical header protection 00155 /// macros. 00156 void InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/, 00157 const Token &/*FilenameTok*/, 00158 SrcMgr::CharacteristicKind /*FileType*/) { 00159 assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't " 00160 "found via an inclusion directive, was skipped"); 00161 FileChanges.erase(LastInsertedFileChange); 00162 LastInsertedFileChange = FileChanges.end(); 00163 } 00164 00165 /// This should be called whenever the preprocessor encounters include 00166 /// directives. It does not say whether the file has been included, but it 00167 /// provides more information about the directive (hash location instead 00168 /// of location inside the included file). It is assumed that the matching 00169 /// FileChanged() or FileSkipped() is called after this. 00170 void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, 00171 const Token &/*IncludeTok*/, 00172 StringRef /*FileName*/, 00173 bool /*IsAngled*/, 00174 CharSourceRange /*FilenameRange*/, 00175 const FileEntry * /*File*/, 00176 StringRef /*SearchPath*/, 00177 StringRef /*RelativePath*/, 00178 const Module *Imported) { 00179 assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " 00180 "directive was found before the previous one was processed"); 00181 std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert( 00182 std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported))); 00183 assert(p.second && "Unexpected revisitation of the same include directive"); 00184 if (!Imported) 00185 LastInsertedFileChange = p.first; 00186 } 00187 00188 /// Simple lookup for a SourceLocation (specifically one denoting the hash in 00189 /// an inclusion directive) in the map of inclusion information, FileChanges. 00190 const InclusionRewriter::FileChange * 00191 InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const { 00192 FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding()); 00193 if (I != FileChanges.end()) 00194 return &I->second; 00195 return nullptr; 00196 } 00197 00198 /// Detect the likely line ending style of \p FromFile by examining the first 00199 /// newline found within it. 00200 static StringRef DetectEOL(const MemoryBuffer &FromFile) { 00201 // Detect what line endings the file uses, so that added content does not mix 00202 // the style. We need to check for "\r\n" first because "\n\r" will match 00203 // "\r\n\r\n". 00204 const char *Pos = strchr(FromFile.getBufferStart(), '\n'); 00205 if (!Pos) 00206 return "\n"; 00207 if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r') 00208 return "\r\n"; 00209 if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r') 00210 return "\n\r"; 00211 return "\n"; 00212 } 00213 00214 void InclusionRewriter::detectMainFileEOL() { 00215 bool Invalid; 00216 const MemoryBuffer &FromFile = *SM.getBuffer(SM.getMainFileID(), &Invalid); 00217 assert(!Invalid); 00218 if (Invalid) 00219 return; // Should never happen, but whatever. 00220 MainEOL = DetectEOL(FromFile); 00221 } 00222 00223 /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at 00224 /// \p WriteTo - 1. 00225 void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, 00226 unsigned &WriteFrom, unsigned WriteTo, 00227 StringRef LocalEOL, int &Line, 00228 bool EnsureNewline) { 00229 if (WriteTo <= WriteFrom) 00230 return; 00231 if (&FromFile == PredefinesBuffer) { 00232 // Ignore the #defines of the predefines buffer. 00233 WriteFrom = WriteTo; 00234 return; 00235 } 00236 00237 // If we would output half of a line ending, advance one character to output 00238 // the whole line ending. All buffers are null terminated, so looking ahead 00239 // one byte is safe. 00240 if (LocalEOL.size() == 2 && 00241 LocalEOL[0] == (FromFile.getBufferStart() + WriteTo)[-1] && 00242 LocalEOL[1] == (FromFile.getBufferStart() + WriteTo)[0]) 00243 WriteTo++; 00244 00245 StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom, 00246 WriteTo - WriteFrom); 00247 00248 if (MainEOL == LocalEOL) { 00249 OS << TextToWrite; 00250 // count lines manually, it's faster than getPresumedLoc() 00251 Line += TextToWrite.count(LocalEOL); 00252 if (EnsureNewline && !TextToWrite.endswith(LocalEOL)) 00253 OS << MainEOL; 00254 } else { 00255 // Output the file one line at a time, rewriting the line endings as we go. 00256 StringRef Rest = TextToWrite; 00257 while (!Rest.empty()) { 00258 StringRef LineText; 00259 std::tie(LineText, Rest) = Rest.split(LocalEOL); 00260 OS << LineText; 00261 Line++; 00262 if (!Rest.empty()) 00263 OS << MainEOL; 00264 } 00265 if (TextToWrite.endswith(LocalEOL) || EnsureNewline) 00266 OS << MainEOL; 00267 } 00268 WriteFrom = WriteTo; 00269 } 00270 00271 /// Print characters from \p FromFile starting at \p NextToWrite up until the 00272 /// inclusion directive at \p StartToken, then print out the inclusion 00273 /// inclusion directive disabled by a #if directive, updating \p NextToWrite 00274 /// and \p Line to track the number of source lines visited and the progress 00275 /// through the \p FromFile buffer. 00276 void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, 00277 const Token &StartToken, 00278 const MemoryBuffer &FromFile, 00279 StringRef LocalEOL, 00280 unsigned &NextToWrite, int &Line) { 00281 OutputContentUpTo(FromFile, NextToWrite, 00282 SM.getFileOffset(StartToken.getLocation()), LocalEOL, Line, 00283 false); 00284 Token DirectiveToken; 00285 do { 00286 DirectiveLex.LexFromRawLexer(DirectiveToken); 00287 } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); 00288 if (&FromFile == PredefinesBuffer) { 00289 // OutputContentUpTo() would not output anything anyway. 00290 return; 00291 } 00292 OS << "#if 0 /* expanded by -frewrite-includes */" << MainEOL; 00293 OutputContentUpTo(FromFile, NextToWrite, 00294 SM.getFileOffset(DirectiveToken.getLocation()) + 00295 DirectiveToken.getLength(), 00296 LocalEOL, Line, true); 00297 OS << "#endif /* expanded by -frewrite-includes */" << MainEOL; 00298 } 00299 00300 /// Find the next identifier in the pragma directive specified by \p RawToken. 00301 StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, 00302 Token &RawToken) { 00303 RawLex.LexFromRawLexer(RawToken); 00304 if (RawToken.is(tok::raw_identifier)) 00305 PP.LookUpIdentifierInfo(RawToken); 00306 if (RawToken.is(tok::identifier)) 00307 return RawToken.getIdentifierInfo()->getName(); 00308 return StringRef(); 00309 } 00310 00311 // Expand __has_include and __has_include_next if possible. If there's no 00312 // definitive answer return false. 00313 bool InclusionRewriter::HandleHasInclude( 00314 FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, 00315 bool &FileExists) { 00316 // Lex the opening paren. 00317 RawLex.LexFromRawLexer(Tok); 00318 if (Tok.isNot(tok::l_paren)) 00319 return false; 00320 00321 RawLex.LexFromRawLexer(Tok); 00322 00323 SmallString<128> FilenameBuffer; 00324 StringRef Filename; 00325 // Since the raw lexer doesn't give us angle_literals we have to parse them 00326 // ourselves. 00327 // FIXME: What to do if the file name is a macro? 00328 if (Tok.is(tok::less)) { 00329 RawLex.LexFromRawLexer(Tok); 00330 00331 FilenameBuffer += '<'; 00332 do { 00333 if (Tok.is(tok::eod)) // Sanity check. 00334 return false; 00335 00336 if (Tok.is(tok::raw_identifier)) 00337 PP.LookUpIdentifierInfo(Tok); 00338 00339 // Get the string piece. 00340 SmallVector<char, 128> TmpBuffer; 00341 bool Invalid = false; 00342 StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); 00343 if (Invalid) 00344 return false; 00345 00346 FilenameBuffer += TmpName; 00347 00348 RawLex.LexFromRawLexer(Tok); 00349 } while (Tok.isNot(tok::greater)); 00350 00351 FilenameBuffer += '>'; 00352 Filename = FilenameBuffer; 00353 } else { 00354 if (Tok.isNot(tok::string_literal)) 00355 return false; 00356 00357 bool Invalid = false; 00358 Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); 00359 if (Invalid) 00360 return false; 00361 } 00362 00363 // Lex the closing paren. 00364 RawLex.LexFromRawLexer(Tok); 00365 if (Tok.isNot(tok::r_paren)) 00366 return false; 00367 00368 // Now ask HeaderInfo if it knows about the header. 00369 // FIXME: Subframeworks aren't handled here. Do we care? 00370 bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); 00371 const DirectoryLookup *CurDir; 00372 const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId); 00373 SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1> 00374 Includers; 00375 Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir())); 00376 const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( 00377 Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr, 00378 nullptr, nullptr, false); 00379 00380 FileExists = File != nullptr; 00381 return true; 00382 } 00383 00384 /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it 00385 /// and including content of included files recursively. 00386 bool InclusionRewriter::Process(FileID FileId, 00387 SrcMgr::CharacteristicKind FileType) 00388 { 00389 bool Invalid; 00390 const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); 00391 if (Invalid) // invalid inclusion 00392 return false; 00393 const char *FileName = FromFile.getBufferIdentifier(); 00394 Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); 00395 RawLex.SetCommentRetentionState(false); 00396 00397 StringRef LocalEOL = DetectEOL(FromFile); 00398 00399 // Per the GNU docs: "1" indicates entering a new file. 00400 if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID()) 00401 WriteLineInfo(FileName, 1, FileType, ""); 00402 else 00403 WriteLineInfo(FileName, 1, FileType, " 1"); 00404 00405 if (SM.getFileIDSize(FileId) == 0) 00406 return false; 00407 00408 // The next byte to be copied from the source file, which may be non-zero if 00409 // the lexer handled a BOM. 00410 unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation()); 00411 assert(SM.getLineNumber(FileId, NextToWrite) == 1); 00412 int Line = 1; // The current input file line number. 00413 00414 Token RawToken; 00415 RawLex.LexFromRawLexer(RawToken); 00416 00417 // TODO: Consider adding a switch that strips possibly unimportant content, 00418 // such as comments, to reduce the size of repro files. 00419 while (RawToken.isNot(tok::eof)) { 00420 if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) { 00421 RawLex.setParsingPreprocessorDirective(true); 00422 Token HashToken = RawToken; 00423 RawLex.LexFromRawLexer(RawToken); 00424 if (RawToken.is(tok::raw_identifier)) 00425 PP.LookUpIdentifierInfo(RawToken); 00426 if (RawToken.getIdentifierInfo() != nullptr) { 00427 switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { 00428 case tok::pp_include: 00429 case tok::pp_include_next: 00430 case tok::pp_import: { 00431 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, NextToWrite, 00432 Line); 00433 if (FileId != PP.getPredefinesFileID()) 00434 WriteLineInfo(FileName, Line - 1, FileType, ""); 00435 StringRef LineInfoExtra; 00436 if (const FileChange *Change = FindFileChangeLocation( 00437 HashToken.getLocation())) { 00438 if (Change->Mod) { 00439 WriteImplicitModuleImport(Change->Mod); 00440 00441 // else now include and recursively process the file 00442 } else if (Process(Change->Id, Change->FileType)) { 00443 // and set lineinfo back to this file, if the nested one was 00444 // actually included 00445 // `2' indicates returning to a file (after having included 00446 // another file. 00447 LineInfoExtra = " 2"; 00448 } 00449 } 00450 // fix up lineinfo (since commented out directive changed line 00451 // numbers) for inclusions that were skipped due to header guards 00452 WriteLineInfo(FileName, Line, FileType, LineInfoExtra); 00453 break; 00454 } 00455 case tok::pp_pragma: { 00456 StringRef Identifier = NextIdentifierName(RawLex, RawToken); 00457 if (Identifier == "clang" || Identifier == "GCC") { 00458 if (NextIdentifierName(RawLex, RawToken) == "system_header") { 00459 // keep the directive in, commented out 00460 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 00461 NextToWrite, Line); 00462 // update our own type 00463 FileType = SM.getFileCharacteristic(RawToken.getLocation()); 00464 WriteLineInfo(FileName, Line, FileType); 00465 } 00466 } else if (Identifier == "once") { 00467 // keep the directive in, commented out 00468 CommentOutDirective(RawLex, HashToken, FromFile, LocalEOL, 00469 NextToWrite, Line); 00470 WriteLineInfo(FileName, Line, FileType); 00471 } 00472 break; 00473 } 00474 case tok::pp_if: 00475 case tok::pp_elif: { 00476 bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() == 00477 tok::pp_elif); 00478 // Rewrite special builtin macros to avoid pulling in host details. 00479 do { 00480 // Walk over the directive. 00481 RawLex.LexFromRawLexer(RawToken); 00482 if (RawToken.is(tok::raw_identifier)) 00483 PP.LookUpIdentifierInfo(RawToken); 00484 00485 if (RawToken.is(tok::identifier)) { 00486 bool HasFile; 00487 SourceLocation Loc = RawToken.getLocation(); 00488 00489 // Rewrite __has_include(x) 00490 if (RawToken.getIdentifierInfo()->isStr("__has_include")) { 00491 if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken, 00492 HasFile)) 00493 continue; 00494 // Rewrite __has_include_next(x) 00495 } else if (RawToken.getIdentifierInfo()->isStr( 00496 "__has_include_next")) { 00497 const DirectoryLookup *Lookup = PP.GetCurDirLookup(); 00498 if (Lookup) 00499 ++Lookup; 00500 00501 if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken, 00502 HasFile)) 00503 continue; 00504 } else { 00505 continue; 00506 } 00507 // Replace the macro with (0) or (1), followed by the commented 00508 // out macro for reference. 00509 OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), 00510 LocalEOL, Line, false); 00511 OS << '(' << (int) HasFile << ")/*"; 00512 OutputContentUpTo(FromFile, NextToWrite, 00513 SM.getFileOffset(RawToken.getLocation()) + 00514 RawToken.getLength(), 00515 LocalEOL, Line, false); 00516 OS << "*/"; 00517 } 00518 } while (RawToken.isNot(tok::eod)); 00519 if (elif) { 00520 OutputContentUpTo(FromFile, NextToWrite, 00521 SM.getFileOffset(RawToken.getLocation()) + 00522 RawToken.getLength(), 00523 LocalEOL, Line, /*EnsureNewline=*/ true); 00524 WriteLineInfo(FileName, Line, FileType); 00525 } 00526 break; 00527 } 00528 case tok::pp_endif: 00529 case tok::pp_else: { 00530 // We surround every #include by #if 0 to comment it out, but that 00531 // changes line numbers. These are fixed up right after that, but 00532 // the whole #include could be inside a preprocessor conditional 00533 // that is not processed. So it is necessary to fix the line 00534 // numbers one the next line after each #else/#endif as well. 00535 RawLex.SetKeepWhitespaceMode(true); 00536 do { 00537 RawLex.LexFromRawLexer(RawToken); 00538 } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof)); 00539 OutputContentUpTo(FromFile, NextToWrite, 00540 SM.getFileOffset(RawToken.getLocation()) + 00541 RawToken.getLength(), 00542 LocalEOL, Line, /*EnsureNewline=*/ true); 00543 WriteLineInfo(FileName, Line, FileType); 00544 RawLex.SetKeepWhitespaceMode(false); 00545 } 00546 default: 00547 break; 00548 } 00549 } 00550 RawLex.setParsingPreprocessorDirective(false); 00551 } 00552 RawLex.LexFromRawLexer(RawToken); 00553 } 00554 OutputContentUpTo(FromFile, NextToWrite, 00555 SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, 00556 Line, /*EnsureNewline=*/true); 00557 return true; 00558 } 00559 00560 /// InclusionRewriterInInput - Implement -frewrite-includes mode. 00561 void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, 00562 const PreprocessorOutputOptions &Opts) { 00563 SourceManager &SM = PP.getSourceManager(); 00564 InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS, 00565 Opts.ShowLineMarkers); 00566 Rewrite->detectMainFileEOL(); 00567 00568 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Rewrite)); 00569 PP.IgnorePragmas(); 00570 00571 // First let the preprocessor process the entire file and call callbacks. 00572 // Callbacks will record which #include's were actually performed. 00573 PP.EnterMainSourceFile(); 00574 Token Tok; 00575 // Only preprocessor directives matter here, so disable macro expansion 00576 // everywhere else as an optimization. 00577 // TODO: It would be even faster if the preprocessor could be switched 00578 // to a mode where it would parse only preprocessor directives and comments, 00579 // nothing else matters for parsing or processing. 00580 PP.SetMacroExpansionOnlyInDirectives(); 00581 do { 00582 PP.Lex(Tok); 00583 } while (Tok.isNot(tok::eof)); 00584 Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); 00585 Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); 00586 Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); 00587 OS->flush(); 00588 }