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