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