Home | History | Annotate | Download | only in Rewrite
      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   /// Used transitively for building up the FileIncludes mapping over the
     50   /// various \c PPCallbacks callbacks.
     51   SourceLocation LastInclusionLocation;
     52 public:
     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();
     60 private:
     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.
     93 InclusionRewriter::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.
    105 void 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 
    134 void 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.
    141 void 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.
    160 void 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.
    173 void 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.
    196 const InclusionRewriter::IncludedFile *
    197 InclusionRewriter::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.
    206 const Module *
    207 InclusionRewriter::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.
    216 static 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 
    230 void 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.
    241 void 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.
    292 void 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.
    317 StringRef 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.
    329 bool 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.
    403 bool 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.
    576 void 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