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