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