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