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