1243791Sdim//===--- InclusionRewriter.cpp - Rewrite includes into their expansions ---===//
2243791Sdim//
3243791Sdim//                     The LLVM Compiler Infrastructure
4243791Sdim//
5243791Sdim// This file is distributed under the University of Illinois Open Source
6243791Sdim// License. See LICENSE.TXT for details.
7243791Sdim//
8243791Sdim//===----------------------------------------------------------------------===//
9243791Sdim//
10243791Sdim// This code rewrites include invocations into their expansions.  This gives you
11243791Sdim// a file with all included files merged into it.
12243791Sdim//
13243791Sdim//===----------------------------------------------------------------------===//
14243791Sdim
15243791Sdim#include "clang/Rewrite/Frontend/Rewriters.h"
16243791Sdim#include "clang/Basic/SourceManager.h"
17243791Sdim#include "clang/Frontend/PreprocessorOutputOptions.h"
18251662Sdim#include "clang/Lex/HeaderSearch.h"
19263508Sdim#include "clang/Lex/Pragma.h"
20249423Sdim#include "clang/Lex/Preprocessor.h"
21251662Sdim#include "llvm/ADT/SmallString.h"
22243791Sdim#include "llvm/Support/raw_ostream.h"
23243791Sdim
24243791Sdimusing namespace clang;
25243791Sdimusing namespace llvm;
26243791Sdim
27243791Sdimnamespace {
28243791Sdim
29243791Sdimclass InclusionRewriter : public PPCallbacks {
30243791Sdim  /// Information about which #includes were actually performed,
31243791Sdim  /// created by preprocessor callbacks.
32243791Sdim  struct FileChange {
33251662Sdim    const Module *Mod;
34243791Sdim    SourceLocation From;
35243791Sdim    FileID Id;
36243791Sdim    SrcMgr::CharacteristicKind FileType;
37251662Sdim    FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) {
38243791Sdim    }
39243791Sdim  };
40243791Sdim  Preprocessor &PP; ///< Used to find inclusion directives.
41243791Sdim  SourceManager &SM; ///< Used to read and manage source files.
42243791Sdim  raw_ostream &OS; ///< The destination stream for rewritten contents.
43263508Sdim  const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines.
44243791Sdim  bool ShowLineMarkers; ///< Show #line markers.
45243791Sdim  bool UseLineDirective; ///< Use of line directives or line markers.
46243791Sdim  typedef std::map<unsigned, FileChange> FileChangeMap;
47249423Sdim  FileChangeMap FileChanges; ///< Tracks which files were included where.
48243791Sdim  /// Used transitively for building up the FileChanges mapping over the
49243791Sdim  /// various \c PPCallbacks callbacks.
50243791Sdim  FileChangeMap::iterator LastInsertedFileChange;
51243791Sdimpublic:
52243791Sdim  InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers);
53243791Sdim  bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
54263508Sdim  void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
55263508Sdim    PredefinesBuffer = Buf;
56263508Sdim  }
57243791Sdimprivate:
58243791Sdim  virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
59243791Sdim                           SrcMgr::CharacteristicKind FileType,
60243791Sdim                           FileID PrevFID);
61243791Sdim  virtual void FileSkipped(const FileEntry &ParentFile,
62243791Sdim                           const Token &FilenameTok,
63243791Sdim                           SrcMgr::CharacteristicKind FileType);
64243791Sdim  virtual void InclusionDirective(SourceLocation HashLoc,
65243791Sdim                                  const Token &IncludeTok,
66243791Sdim                                  StringRef FileName,
67243791Sdim                                  bool IsAngled,
68243791Sdim                                  CharSourceRange FilenameRange,
69243791Sdim                                  const FileEntry *File,
70243791Sdim                                  StringRef SearchPath,
71243791Sdim                                  StringRef RelativePath,
72243791Sdim                                  const Module *Imported);
73243791Sdim  void WriteLineInfo(const char *Filename, int Line,
74243791Sdim                     SrcMgr::CharacteristicKind FileType,
75243791Sdim                     StringRef EOL, StringRef Extra = StringRef());
76251662Sdim  void WriteImplicitModuleImport(const Module *Mod, StringRef EOL);
77243791Sdim  void OutputContentUpTo(const MemoryBuffer &FromFile,
78243791Sdim                         unsigned &WriteFrom, unsigned WriteTo,
79243791Sdim                         StringRef EOL, int &lines,
80243791Sdim                         bool EnsureNewline = false);
81243791Sdim  void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
82243791Sdim                           const MemoryBuffer &FromFile, StringRef EOL,
83243791Sdim                           unsigned &NextToWrite, int &Lines);
84251662Sdim  bool HandleHasInclude(FileID FileId, Lexer &RawLex,
85251662Sdim                        const DirectoryLookup *Lookup, Token &Tok,
86251662Sdim                        bool &FileExists);
87243791Sdim  const FileChange *FindFileChangeLocation(SourceLocation Loc) const;
88243791Sdim  StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
89243791Sdim};
90243791Sdim
91243791Sdim}  // end anonymous namespace
92243791Sdim
93243791Sdim/// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
94243791SdimInclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
95243791Sdim                                     bool ShowLineMarkers)
96263508Sdim    : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(0),
97243791Sdim    ShowLineMarkers(ShowLineMarkers),
98243791Sdim    LastInsertedFileChange(FileChanges.end()) {
99243791Sdim  // If we're in microsoft mode, use normal #line instead of line markers.
100243791Sdim  UseLineDirective = PP.getLangOpts().MicrosoftExt;
101243791Sdim}
102243791Sdim
103243791Sdim/// Write appropriate line information as either #line directives or GNU line
104243791Sdim/// markers depending on what mode we're in, including the \p Filename and
105243791Sdim/// \p Line we are located at, using the specified \p EOL line separator, and
106243791Sdim/// any \p Extra context specifiers in GNU line directives.
107243791Sdimvoid InclusionRewriter::WriteLineInfo(const char *Filename, int Line,
108243791Sdim                                      SrcMgr::CharacteristicKind FileType,
109243791Sdim                                      StringRef EOL, StringRef Extra) {
110243791Sdim  if (!ShowLineMarkers)
111243791Sdim    return;
112243791Sdim  if (UseLineDirective) {
113263508Sdim    OS << "#line" << ' ' << Line << ' ' << '"';
114263508Sdim    OS.write_escaped(Filename);
115263508Sdim    OS << '"';
116243791Sdim  } else {
117243791Sdim    // Use GNU linemarkers as described here:
118243791Sdim    // http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
119263508Sdim    OS << '#' << ' ' << Line << ' ' << '"';
120263508Sdim    OS.write_escaped(Filename);
121263508Sdim    OS << '"';
122243791Sdim    if (!Extra.empty())
123243791Sdim      OS << Extra;
124243791Sdim    if (FileType == SrcMgr::C_System)
125243791Sdim      // "`3' This indicates that the following text comes from a system header
126243791Sdim      // file, so certain warnings should be suppressed."
127243791Sdim      OS << " 3";
128243791Sdim    else if (FileType == SrcMgr::C_ExternCSystem)
129243791Sdim      // as above for `3', plus "`4' This indicates that the following text
130243791Sdim      // should be treated as being wrapped in an implicit extern "C" block."
131243791Sdim      OS << " 3 4";
132243791Sdim  }
133243791Sdim  OS << EOL;
134243791Sdim}
135243791Sdim
136251662Sdimvoid InclusionRewriter::WriteImplicitModuleImport(const Module *Mod,
137251662Sdim                                                  StringRef EOL) {
138251662Sdim  OS << "@import " << Mod->getFullModuleName() << ";"
139251662Sdim     << " /* clang -frewrite-includes: implicit import */" << EOL;
140251662Sdim}
141251662Sdim
142243791Sdim/// FileChanged - Whenever the preprocessor enters or exits a #include file
143243791Sdim/// it invokes this handler.
144243791Sdimvoid InclusionRewriter::FileChanged(SourceLocation Loc,
145243791Sdim                                    FileChangeReason Reason,
146243791Sdim                                    SrcMgr::CharacteristicKind NewFileType,
147243791Sdim                                    FileID) {
148243791Sdim  if (Reason != EnterFile)
149243791Sdim    return;
150243791Sdim  if (LastInsertedFileChange == FileChanges.end())
151243791Sdim    // we didn't reach this file (eg: the main file) via an inclusion directive
152243791Sdim    return;
153243791Sdim  LastInsertedFileChange->second.Id = FullSourceLoc(Loc, SM).getFileID();
154243791Sdim  LastInsertedFileChange->second.FileType = NewFileType;
155243791Sdim  LastInsertedFileChange = FileChanges.end();
156243791Sdim}
157243791Sdim
158243791Sdim/// Called whenever an inclusion is skipped due to canonical header protection
159243791Sdim/// macros.
160243791Sdimvoid InclusionRewriter::FileSkipped(const FileEntry &/*ParentFile*/,
161243791Sdim                                    const Token &/*FilenameTok*/,
162243791Sdim                                    SrcMgr::CharacteristicKind /*FileType*/) {
163243791Sdim  assert(LastInsertedFileChange != FileChanges.end() && "A file, that wasn't "
164243791Sdim    "found via an inclusion directive, was skipped");
165243791Sdim  FileChanges.erase(LastInsertedFileChange);
166243791Sdim  LastInsertedFileChange = FileChanges.end();
167243791Sdim}
168243791Sdim
169243791Sdim/// This should be called whenever the preprocessor encounters include
170243791Sdim/// directives. It does not say whether the file has been included, but it
171243791Sdim/// provides more information about the directive (hash location instead
172243791Sdim/// of location inside the included file). It is assumed that the matching
173243791Sdim/// FileChanged() or FileSkipped() is called after this.
174243791Sdimvoid InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
175243791Sdim                                           const Token &/*IncludeTok*/,
176243791Sdim                                           StringRef /*FileName*/,
177243791Sdim                                           bool /*IsAngled*/,
178243791Sdim                                           CharSourceRange /*FilenameRange*/,
179243791Sdim                                           const FileEntry * /*File*/,
180243791Sdim                                           StringRef /*SearchPath*/,
181243791Sdim                                           StringRef /*RelativePath*/,
182251662Sdim                                           const Module *Imported) {
183243791Sdim  assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion "
184243791Sdim    "directive was found before the previous one was processed");
185243791Sdim  std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert(
186251662Sdim    std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported)));
187243791Sdim  assert(p.second && "Unexpected revisitation of the same include directive");
188251662Sdim  if (!Imported)
189251662Sdim    LastInsertedFileChange = p.first;
190243791Sdim}
191243791Sdim
192243791Sdim/// Simple lookup for a SourceLocation (specifically one denoting the hash in
193243791Sdim/// an inclusion directive) in the map of inclusion information, FileChanges.
194243791Sdimconst InclusionRewriter::FileChange *
195243791SdimInclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const {
196243791Sdim  FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding());
197243791Sdim  if (I != FileChanges.end())
198243791Sdim    return &I->second;
199243791Sdim  return NULL;
200243791Sdim}
201243791Sdim
202243791Sdim/// Detect the likely line ending style of \p FromFile by examining the first
203243791Sdim/// newline found within it.
204243791Sdimstatic StringRef DetectEOL(const MemoryBuffer &FromFile) {
205243791Sdim  // detect what line endings the file uses, so that added content does not mix
206243791Sdim  // the style
207243791Sdim  const char *Pos = strchr(FromFile.getBufferStart(), '\n');
208243791Sdim  if (Pos == NULL)
209243791Sdim    return "\n";
210243791Sdim  if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r')
211243791Sdim    return "\n\r";
212243791Sdim  if (Pos - 1 >= FromFile.getBufferStart() && Pos[-1] == '\r')
213243791Sdim    return "\r\n";
214243791Sdim  return "\n";
215243791Sdim}
216243791Sdim
217243791Sdim/// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at
218243791Sdim/// \p WriteTo - 1.
219243791Sdimvoid InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile,
220243791Sdim                                          unsigned &WriteFrom, unsigned WriteTo,
221243791Sdim                                          StringRef EOL, int &Line,
222243791Sdim                                          bool EnsureNewline) {
223243791Sdim  if (WriteTo <= WriteFrom)
224243791Sdim    return;
225263508Sdim  if (&FromFile == PredefinesBuffer) {
226263508Sdim    // Ignore the #defines of the predefines buffer.
227263508Sdim    WriteFrom = WriteTo;
228263508Sdim    return;
229263508Sdim  }
230243791Sdim  OS.write(FromFile.getBufferStart() + WriteFrom, WriteTo - WriteFrom);
231243791Sdim  // count lines manually, it's faster than getPresumedLoc()
232243791Sdim  Line += std::count(FromFile.getBufferStart() + WriteFrom,
233243791Sdim                     FromFile.getBufferStart() + WriteTo, '\n');
234243791Sdim  if (EnsureNewline) {
235243791Sdim    char LastChar = FromFile.getBufferStart()[WriteTo - 1];
236243791Sdim    if (LastChar != '\n' && LastChar != '\r')
237243791Sdim      OS << EOL;
238243791Sdim  }
239243791Sdim  WriteFrom = WriteTo;
240243791Sdim}
241243791Sdim
242243791Sdim/// Print characters from \p FromFile starting at \p NextToWrite up until the
243243791Sdim/// inclusion directive at \p StartToken, then print out the inclusion
244243791Sdim/// inclusion directive disabled by a #if directive, updating \p NextToWrite
245243791Sdim/// and \p Line to track the number of source lines visited and the progress
246243791Sdim/// through the \p FromFile buffer.
247243791Sdimvoid InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
248243791Sdim                                            const Token &StartToken,
249243791Sdim                                            const MemoryBuffer &FromFile,
250243791Sdim                                            StringRef EOL,
251243791Sdim                                            unsigned &NextToWrite, int &Line) {
252243791Sdim  OutputContentUpTo(FromFile, NextToWrite,
253243791Sdim    SM.getFileOffset(StartToken.getLocation()), EOL, Line);
254243791Sdim  Token DirectiveToken;
255243791Sdim  do {
256243791Sdim    DirectiveLex.LexFromRawLexer(DirectiveToken);
257243791Sdim  } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
258243791Sdim  OS << "#if 0 /* expanded by -frewrite-includes */" << EOL;
259243791Sdim  OutputContentUpTo(FromFile, NextToWrite,
260243791Sdim    SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(),
261243791Sdim    EOL, Line);
262243791Sdim  OS << "#endif /* expanded by -frewrite-includes */" << EOL;
263243791Sdim}
264243791Sdim
265243791Sdim/// Find the next identifier in the pragma directive specified by \p RawToken.
266243791SdimStringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex,
267243791Sdim                                                Token &RawToken) {
268243791Sdim  RawLex.LexFromRawLexer(RawToken);
269243791Sdim  if (RawToken.is(tok::raw_identifier))
270243791Sdim    PP.LookUpIdentifierInfo(RawToken);
271243791Sdim  if (RawToken.is(tok::identifier))
272243791Sdim    return RawToken.getIdentifierInfo()->getName();
273243791Sdim  return StringRef();
274243791Sdim}
275243791Sdim
276251662Sdim// Expand __has_include and __has_include_next if possible. If there's no
277251662Sdim// definitive answer return false.
278251662Sdimbool InclusionRewriter::HandleHasInclude(
279251662Sdim    FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok,
280251662Sdim    bool &FileExists) {
281251662Sdim  // Lex the opening paren.
282251662Sdim  RawLex.LexFromRawLexer(Tok);
283251662Sdim  if (Tok.isNot(tok::l_paren))
284251662Sdim    return false;
285251662Sdim
286251662Sdim  RawLex.LexFromRawLexer(Tok);
287251662Sdim
288251662Sdim  SmallString<128> FilenameBuffer;
289251662Sdim  StringRef Filename;
290251662Sdim  // Since the raw lexer doesn't give us angle_literals we have to parse them
291251662Sdim  // ourselves.
292251662Sdim  // FIXME: What to do if the file name is a macro?
293251662Sdim  if (Tok.is(tok::less)) {
294251662Sdim    RawLex.LexFromRawLexer(Tok);
295251662Sdim
296251662Sdim    FilenameBuffer += '<';
297251662Sdim    do {
298251662Sdim      if (Tok.is(tok::eod)) // Sanity check.
299251662Sdim        return false;
300251662Sdim
301251662Sdim      if (Tok.is(tok::raw_identifier))
302251662Sdim        PP.LookUpIdentifierInfo(Tok);
303251662Sdim
304251662Sdim      // Get the string piece.
305251662Sdim      SmallVector<char, 128> TmpBuffer;
306251662Sdim      bool Invalid = false;
307251662Sdim      StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid);
308251662Sdim      if (Invalid)
309251662Sdim        return false;
310251662Sdim
311251662Sdim      FilenameBuffer += TmpName;
312251662Sdim
313251662Sdim      RawLex.LexFromRawLexer(Tok);
314251662Sdim    } while (Tok.isNot(tok::greater));
315251662Sdim
316251662Sdim    FilenameBuffer += '>';
317251662Sdim    Filename = FilenameBuffer;
318251662Sdim  } else {
319251662Sdim    if (Tok.isNot(tok::string_literal))
320251662Sdim      return false;
321251662Sdim
322251662Sdim    bool Invalid = false;
323251662Sdim    Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
324251662Sdim    if (Invalid)
325251662Sdim      return false;
326251662Sdim  }
327251662Sdim
328251662Sdim  // Lex the closing paren.
329251662Sdim  RawLex.LexFromRawLexer(Tok);
330251662Sdim  if (Tok.isNot(tok::r_paren))
331251662Sdim    return false;
332251662Sdim
333251662Sdim  // Now ask HeaderInfo if it knows about the header.
334251662Sdim  // FIXME: Subframeworks aren't handled here. Do we care?
335251662Sdim  bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
336251662Sdim  const DirectoryLookup *CurDir;
337251662Sdim  const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
338251662Sdim      Filename, isAngled, 0, CurDir,
339251662Sdim      PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false);
340251662Sdim
341251662Sdim  FileExists = File != 0;
342251662Sdim  return true;
343251662Sdim}
344251662Sdim
345263508Sdim/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
346243791Sdim/// and including content of included files recursively.
347243791Sdimbool InclusionRewriter::Process(FileID FileId,
348243791Sdim                                SrcMgr::CharacteristicKind FileType)
349243791Sdim{
350243791Sdim  bool Invalid;
351243791Sdim  const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid);
352243791Sdim  if (Invalid) // invalid inclusion
353251662Sdim    return false;
354243791Sdim  const char *FileName = FromFile.getBufferIdentifier();
355243791Sdim  Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts());
356243791Sdim  RawLex.SetCommentRetentionState(false);
357243791Sdim
358243791Sdim  StringRef EOL = DetectEOL(FromFile);
359243791Sdim
360243791Sdim  // Per the GNU docs: "1" indicates the start of a new file.
361243791Sdim  WriteLineInfo(FileName, 1, FileType, EOL, " 1");
362243791Sdim
363243791Sdim  if (SM.getFileIDSize(FileId) == 0)
364251662Sdim    return false;
365243791Sdim
366243791Sdim  // The next byte to be copied from the source file
367243791Sdim  unsigned NextToWrite = 0;
368243791Sdim  int Line = 1; // The current input file line number.
369243791Sdim
370263508Sdim  // Ignore UTF-8 BOM, otherwise it'd end up somewhere else than the start
371263508Sdim  // of the resulting file.
372263508Sdim  if (FromFile.getBuffer().startswith("\xEF\xBB\xBF"))
373263508Sdim    NextToWrite = 3;
374263508Sdim
375243791Sdim  Token RawToken;
376243791Sdim  RawLex.LexFromRawLexer(RawToken);
377243791Sdim
378243791Sdim  // TODO: Consider adding a switch that strips possibly unimportant content,
379243791Sdim  // such as comments, to reduce the size of repro files.
380243791Sdim  while (RawToken.isNot(tok::eof)) {
381243791Sdim    if (RawToken.is(tok::hash) && RawToken.isAtStartOfLine()) {
382243791Sdim      RawLex.setParsingPreprocessorDirective(true);
383243791Sdim      Token HashToken = RawToken;
384243791Sdim      RawLex.LexFromRawLexer(RawToken);
385243791Sdim      if (RawToken.is(tok::raw_identifier))
386243791Sdim        PP.LookUpIdentifierInfo(RawToken);
387263508Sdim      if (RawToken.getIdentifierInfo() != NULL) {
388243791Sdim        switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
389243791Sdim          case tok::pp_include:
390243791Sdim          case tok::pp_include_next:
391243791Sdim          case tok::pp_import: {
392243791Sdim            CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite,
393243791Sdim              Line);
394251662Sdim            StringRef LineInfoExtra;
395243791Sdim            if (const FileChange *Change = FindFileChangeLocation(
396243791Sdim                HashToken.getLocation())) {
397251662Sdim              if (Change->Mod) {
398251662Sdim                WriteImplicitModuleImport(Change->Mod, EOL);
399251662Sdim
400251662Sdim              // else now include and recursively process the file
401251662Sdim              } else if (Process(Change->Id, Change->FileType)) {
402243791Sdim                // and set lineinfo back to this file, if the nested one was
403243791Sdim                // actually included
404243791Sdim                // `2' indicates returning to a file (after having included
405243791Sdim                // another file.
406251662Sdim                LineInfoExtra = " 2";
407251662Sdim              }
408251662Sdim            }
409251662Sdim            // fix up lineinfo (since commented out directive changed line
410251662Sdim            // numbers) for inclusions that were skipped due to header guards
411251662Sdim            WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra);
412243791Sdim            break;
413243791Sdim          }
414243791Sdim          case tok::pp_pragma: {
415243791Sdim            StringRef Identifier = NextIdentifierName(RawLex, RawToken);
416243791Sdim            if (Identifier == "clang" || Identifier == "GCC") {
417243791Sdim              if (NextIdentifierName(RawLex, RawToken) == "system_header") {
418243791Sdim                // keep the directive in, commented out
419243791Sdim                CommentOutDirective(RawLex, HashToken, FromFile, EOL,
420243791Sdim                  NextToWrite, Line);
421243791Sdim                // update our own type
422243791Sdim                FileType = SM.getFileCharacteristic(RawToken.getLocation());
423243791Sdim                WriteLineInfo(FileName, Line, FileType, EOL);
424243791Sdim              }
425243791Sdim            } else if (Identifier == "once") {
426243791Sdim              // keep the directive in, commented out
427243791Sdim              CommentOutDirective(RawLex, HashToken, FromFile, EOL,
428243791Sdim                NextToWrite, Line);
429243791Sdim              WriteLineInfo(FileName, Line, FileType, EOL);
430243791Sdim            }
431243791Sdim            break;
432243791Sdim          }
433251662Sdim          case tok::pp_if:
434263508Sdim          case tok::pp_elif: {
435263508Sdim            bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() ==
436263508Sdim                         tok::pp_elif);
437251662Sdim            // Rewrite special builtin macros to avoid pulling in host details.
438251662Sdim            do {
439251662Sdim              // Walk over the directive.
440251662Sdim              RawLex.LexFromRawLexer(RawToken);
441251662Sdim              if (RawToken.is(tok::raw_identifier))
442251662Sdim                PP.LookUpIdentifierInfo(RawToken);
443251662Sdim
444251662Sdim              if (RawToken.is(tok::identifier)) {
445251662Sdim                bool HasFile;
446251662Sdim                SourceLocation Loc = RawToken.getLocation();
447251662Sdim
448251662Sdim                // Rewrite __has_include(x)
449251662Sdim                if (RawToken.getIdentifierInfo()->isStr("__has_include")) {
450251662Sdim                  if (!HandleHasInclude(FileId, RawLex, 0, RawToken, HasFile))
451251662Sdim                    continue;
452251662Sdim                  // Rewrite __has_include_next(x)
453251662Sdim                } else if (RawToken.getIdentifierInfo()->isStr(
454251662Sdim                               "__has_include_next")) {
455251662Sdim                  const DirectoryLookup *Lookup = PP.GetCurDirLookup();
456251662Sdim                  if (Lookup)
457251662Sdim                    ++Lookup;
458251662Sdim
459251662Sdim                  if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken,
460251662Sdim                                        HasFile))
461251662Sdim                    continue;
462251662Sdim                } else {
463251662Sdim                  continue;
464251662Sdim                }
465251662Sdim                // Replace the macro with (0) or (1), followed by the commented
466251662Sdim                // out macro for reference.
467251662Sdim                OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
468251662Sdim                                  EOL, Line);
469251662Sdim                OS << '(' << (int) HasFile << ")/*";
470251662Sdim                OutputContentUpTo(FromFile, NextToWrite,
471251662Sdim                                  SM.getFileOffset(RawToken.getLocation()) +
472251662Sdim                                  RawToken.getLength(),
473251662Sdim                                  EOL, Line);
474251662Sdim                OS << "*/";
475251662Sdim              }
476251662Sdim            } while (RawToken.isNot(tok::eod));
477263508Sdim            if (elif) {
478263508Sdim              OutputContentUpTo(FromFile, NextToWrite,
479263508Sdim                                SM.getFileOffset(RawToken.getLocation()) +
480263508Sdim                                    RawToken.getLength(),
481263508Sdim                                EOL, Line, /*EnsureNewLine*/ true);
482263508Sdim              WriteLineInfo(FileName, Line, FileType, EOL);
483263508Sdim            }
484251662Sdim            break;
485263508Sdim          }
486263508Sdim          case tok::pp_endif:
487263508Sdim          case tok::pp_else: {
488263508Sdim            // We surround every #include by #if 0 to comment it out, but that
489263508Sdim            // changes line numbers. These are fixed up right after that, but
490263508Sdim            // the whole #include could be inside a preprocessor conditional
491263508Sdim            // that is not processed. So it is necessary to fix the line
492263508Sdim            // numbers one the next line after each #else/#endif as well.
493263508Sdim            RawLex.SetKeepWhitespaceMode(true);
494263508Sdim            do {
495263508Sdim              RawLex.LexFromRawLexer(RawToken);
496263508Sdim            } while (RawToken.isNot(tok::eod) && RawToken.isNot(tok::eof));
497263508Sdim            OutputContentUpTo(
498263508Sdim                FromFile, NextToWrite,
499263508Sdim                SM.getFileOffset(RawToken.getLocation()) + RawToken.getLength(),
500263508Sdim                EOL, Line, /*EnsureNewLine*/ true);
501263508Sdim            WriteLineInfo(FileName, Line, FileType, EOL);
502263508Sdim            RawLex.SetKeepWhitespaceMode(false);
503263508Sdim          }
504243791Sdim          default:
505243791Sdim            break;
506243791Sdim        }
507243791Sdim      }
508243791Sdim      RawLex.setParsingPreprocessorDirective(false);
509243791Sdim    }
510243791Sdim    RawLex.LexFromRawLexer(RawToken);
511243791Sdim  }
512243791Sdim  OutputContentUpTo(FromFile, NextToWrite,
513263508Sdim    SM.getFileOffset(SM.getLocForEndOfFile(FileId)), EOL, Line,
514243791Sdim    /*EnsureNewline*/true);
515243791Sdim  return true;
516243791Sdim}
517243791Sdim
518243791Sdim/// InclusionRewriterInInput - Implement -frewrite-includes mode.
519243791Sdimvoid clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
520243791Sdim                                   const PreprocessorOutputOptions &Opts) {
521243791Sdim  SourceManager &SM = PP.getSourceManager();
522243791Sdim  InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS,
523243791Sdim                                                     Opts.ShowLineMarkers);
524243791Sdim  PP.addPPCallbacks(Rewrite);
525263508Sdim  // Ignore all pragmas, otherwise there will be warnings about unknown pragmas
526263508Sdim  // (because there's nothing to handle them).
527263508Sdim  PP.AddPragmaHandler(new EmptyPragmaHandler());
528263508Sdim  // Ignore also all pragma in all namespaces created
529263508Sdim  // in Preprocessor::RegisterBuiltinPragmas().
530263508Sdim  PP.AddPragmaHandler("GCC", new EmptyPragmaHandler());
531263508Sdim  PP.AddPragmaHandler("clang", new EmptyPragmaHandler());
532243791Sdim
533243791Sdim  // First let the preprocessor process the entire file and call callbacks.
534243791Sdim  // Callbacks will record which #include's were actually performed.
535243791Sdim  PP.EnterMainSourceFile();
536243791Sdim  Token Tok;
537243791Sdim  // Only preprocessor directives matter here, so disable macro expansion
538243791Sdim  // everywhere else as an optimization.
539243791Sdim  // TODO: It would be even faster if the preprocessor could be switched
540243791Sdim  // to a mode where it would parse only preprocessor directives and comments,
541243791Sdim  // nothing else matters for parsing or processing.
542243791Sdim  PP.SetMacroExpansionOnlyInDirectives();
543243791Sdim  do {
544243791Sdim    PP.Lex(Tok);
545243791Sdim  } while (Tok.isNot(tok::eof));
546263508Sdim  Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
547263508Sdim  Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
548243791Sdim  Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User);
549243791Sdim  OS->flush();
550243791Sdim}
551