clang API Documentation

InclusionRewriter.cpp
Go to the documentation of this file.
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 }