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