clang-tools  10.0.0svn
ExpandModularHeadersPPCallbacks.cpp
Go to the documentation of this file.
1 //===- ExpandModularHeadersPPCallbacks.h - clang-tidy -----------*- C++ -*-===//
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 
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/PreprocessorOptions.h"
12 #include "clang/Serialization/ASTReader.h"
13 
14 namespace clang {
15 namespace tooling {
16 
18 public:
19  /// Records that a given file entry is needed for replaying callbacks.
20  void addNecessaryFile(const FileEntry *File) { FilesToRecord.insert(File); }
21 
22  /// Records content for a file and adds it to the FileSystem.
23  void recordFileContent(const FileEntry *File,
24  const SrcMgr::ContentCache &ContentCache,
25  llvm::vfs::InMemoryFileSystem &InMemoryFs) {
26  // Return if we are not interested in the contents of this file.
27  if (!FilesToRecord.count(File))
28  return;
29 
30  // FIXME: Why is this happening? We might be losing contents here.
31  if (!ContentCache.getRawBuffer())
32  return;
33 
34  InMemoryFs.addFile(File->getName(), /*ModificationTime=*/0,
35  llvm::MemoryBuffer::getMemBufferCopy(
36  ContentCache.getRawBuffer()->getBuffer()));
37  // Remove the file from the set of necessary files.
38  FilesToRecord.erase(File);
39  }
40 
41  /// Makes sure we have contents for all the files we were interested in. Ideally
42  /// `FilesToRecord` should be empty.
44  for (auto FileEntry : FilesToRecord)
45  llvm::errs() << "Did not record contents for input file: "
46  << FileEntry->getName() << "\n";
47  }
48 
49 private:
50  /// A set of files whose contents are to be recorded.
51  llvm::DenseSet<const FileEntry *> FilesToRecord;
52 };
53 
55  CompilerInstance *CI,
56  IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
57  : Recorder(std::make_unique<FileRecorder>()), Compiler(*CI),
58  InMemoryFs(new llvm::vfs::InMemoryFileSystem),
59  Sources(Compiler.getSourceManager()),
60  // Forward the new diagnostics to the original DiagnosticConsumer.
61  Diags(new DiagnosticIDs, new DiagnosticOptions,
62  new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
63  LangOpts(Compiler.getLangOpts()) {
64  // Add a FileSystem containing the extra files needed in place of modular
65  // headers.
66  OverlayFS->pushOverlay(InMemoryFs);
67 
68  Diags.setSourceManager(&Sources);
69 
70  LangOpts.Modules = false;
71 
72  auto HSO = std::make_shared<HeaderSearchOptions>();
73  *HSO = Compiler.getHeaderSearchOpts();
74 
75  HeaderInfo = std::make_unique<HeaderSearch>(HSO, Sources, Diags, LangOpts,
76  &Compiler.getTarget());
77 
78  auto PO = std::make_shared<PreprocessorOptions>();
79  *PO = Compiler.getPreprocessorOpts();
80 
81  PP = std::make_unique<clang::Preprocessor>(PO, Diags, LangOpts, Sources,
82  *HeaderInfo, ModuleLoader,
83  /*IILookup=*/nullptr,
84  /*OwnsHeaderSearch=*/false);
85  PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
86  InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
87  Compiler.getFrontendOpts());
88  ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
89  Compiler.getTarget().getTriple());
90 }
91 
93 
95  return PP.get();
96 }
97 
98 void ExpandModularHeadersPPCallbacks::handleModuleFile(
99  serialization::ModuleFile *MF) {
100  if (!MF)
101  return;
102  // Avoid processing a ModuleFile more than once.
103  if (VisitedModules.count(MF))
104  return;
105  VisitedModules.insert(MF);
106 
107  // Visit all the input files of this module and mark them to record their
108  // contents later.
109  Compiler.getModuleManager()->visitInputFiles(
110  *MF, true, false,
111  [this](const serialization::InputFile &IF, bool /*IsSystem*/) {
112  Recorder->addNecessaryFile(IF.getFile());
113  });
114  // Recursively handle all transitively imported modules.
115  for (auto Import : MF->Imports)
116  handleModuleFile(Import);
117 }
118 
119 void ExpandModularHeadersPPCallbacks::parseToLocation(SourceLocation Loc) {
120  // Load all source locations present in the external sources.
121  for (unsigned I = 0, N = Sources.loaded_sloc_entry_size(); I != N; ++I) {
122  Sources.getLoadedSLocEntry(I, nullptr);
123  }
124  // Record contents of files we are interested in and add to the FileSystem.
125  for (auto It = Sources.fileinfo_begin(); It != Sources.fileinfo_end(); ++It) {
126  Recorder->recordFileContent(It->getFirst(), *It->getSecond(), *InMemoryFs);
127  }
128  Recorder->checkAllFilesRecorded();
129 
130  if (!StartedLexing) {
131  StartedLexing = true;
132  PP->Lex(CurrentToken);
133  }
134  while (!CurrentToken.is(tok::eof) &&
135  Sources.isBeforeInTranslationUnit(CurrentToken.getLocation(), Loc)) {
136  PP->Lex(CurrentToken);
137  }
138 }
139 
140 void ExpandModularHeadersPPCallbacks::FileChanged(
141  SourceLocation Loc, FileChangeReason Reason,
142  SrcMgr::CharacteristicKind FileType, FileID PrevFID = FileID()) {
143  if (!EnteredMainFile) {
144  EnteredMainFile = true;
145  PP->EnterMainSourceFile();
146  }
147 }
148 
149 void ExpandModularHeadersPPCallbacks::InclusionDirective(
150  SourceLocation DirectiveLoc, const Token &IncludeToken,
151  StringRef IncludedFilename, bool IsAngled, CharSourceRange FilenameRange,
152  const FileEntry *IncludedFile, StringRef SearchPath, StringRef RelativePath,
153  const Module *Imported, SrcMgr::CharacteristicKind FileType) {
154  if (Imported) {
155  serialization::ModuleFile *MF =
156  Compiler.getModuleManager()->getModuleManager().lookup(
157  Imported->getASTFile());
158  handleModuleFile(MF);
159  }
160  parseToLocation(DirectiveLoc);
161 }
162 
163 void ExpandModularHeadersPPCallbacks::EndOfMainFile() {
164  while (!CurrentToken.is(tok::eof))
165  PP->Lex(CurrentToken);
166 }
167 
168 // Handle all other callbacks.
169 // Just parse to the corresponding location to generate the same callback for
170 // the PPCallbacks registered in our custom preprocessor.
171 void ExpandModularHeadersPPCallbacks::Ident(SourceLocation Loc, StringRef) {
172  parseToLocation(Loc);
173 }
174 void ExpandModularHeadersPPCallbacks::PragmaDirective(SourceLocation Loc,
175  PragmaIntroducerKind) {
176  parseToLocation(Loc);
177 }
178 void ExpandModularHeadersPPCallbacks::PragmaComment(SourceLocation Loc,
179  const IdentifierInfo *,
180  StringRef) {
181  parseToLocation(Loc);
182 }
183 void ExpandModularHeadersPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
184  StringRef,
185  StringRef) {
186  parseToLocation(Loc);
187 }
188 void ExpandModularHeadersPPCallbacks::PragmaDebug(SourceLocation Loc,
189  StringRef) {
190  parseToLocation(Loc);
191 }
192 void ExpandModularHeadersPPCallbacks::PragmaMessage(SourceLocation Loc,
193  StringRef,
194  PragmaMessageKind,
195  StringRef) {
196  parseToLocation(Loc);
197 }
198 void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPush(SourceLocation Loc,
199  StringRef) {
200  parseToLocation(Loc);
201 }
202 void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPop(SourceLocation Loc,
203  StringRef) {
204  parseToLocation(Loc);
205 }
206 void ExpandModularHeadersPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
207  StringRef,
208  diag::Severity,
209  StringRef) {
210  parseToLocation(Loc);
211 }
212 void ExpandModularHeadersPPCallbacks::HasInclude(SourceLocation Loc, StringRef,
213  bool, Optional<FileEntryRef>,
214  SrcMgr::CharacteristicKind) {
215  parseToLocation(Loc);
216 }
217 void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
218  SourceLocation NameLoc, const IdentifierInfo *, SourceLocation StateLoc,
219  unsigned) {
220  // FIME: Figure out whether it's the right location to parse to.
221  parseToLocation(NameLoc);
222 }
223 void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc,
224  StringRef, ArrayRef<int>) {
225  parseToLocation(Loc);
226 }
227 void ExpandModularHeadersPPCallbacks::PragmaWarningPush(SourceLocation Loc,
228  int) {
229  parseToLocation(Loc);
230 }
231 void ExpandModularHeadersPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
232  parseToLocation(Loc);
233 }
234 void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullBegin(
235  SourceLocation Loc) {
236  parseToLocation(Loc);
237 }
238 void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullEnd(
239  SourceLocation Loc) {
240  parseToLocation(Loc);
241 }
242 void ExpandModularHeadersPPCallbacks::MacroExpands(const Token &MacroNameTok,
243  const MacroDefinition &,
244  SourceRange Range,
245  const MacroArgs *) {
246  // FIME: Figure out whether it's the right location to parse to.
247  parseToLocation(Range.getBegin());
248 }
249 void ExpandModularHeadersPPCallbacks::MacroDefined(const Token &MacroNameTok,
250  const MacroDirective *MD) {
251  parseToLocation(MD->getLocation());
252 }
253 void ExpandModularHeadersPPCallbacks::MacroUndefined(
254  const Token &, const MacroDefinition &, const MacroDirective *Undef) {
255  if (Undef)
256  parseToLocation(Undef->getLocation());
257 }
258 void ExpandModularHeadersPPCallbacks::Defined(const Token &MacroNameTok,
259  const MacroDefinition &,
260  SourceRange Range) {
261  // FIME: Figure out whether it's the right location to parse to.
262  parseToLocation(Range.getBegin());
263 }
264 void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
265  SourceRange Range, SourceLocation EndifLoc) {
266  // FIME: Figure out whether it's the right location to parse to.
267  parseToLocation(EndifLoc);
268 }
269 void ExpandModularHeadersPPCallbacks::If(SourceLocation Loc, SourceRange,
270  ConditionValueKind) {
271  parseToLocation(Loc);
272 }
273 void ExpandModularHeadersPPCallbacks::Elif(SourceLocation Loc, SourceRange,
274  ConditionValueKind, SourceLocation) {
275  parseToLocation(Loc);
276 }
277 void ExpandModularHeadersPPCallbacks::Ifdef(SourceLocation Loc, const Token &,
278  const MacroDefinition &) {
279  parseToLocation(Loc);
280 }
281 void ExpandModularHeadersPPCallbacks::Ifndef(SourceLocation Loc, const Token &,
282  const MacroDefinition &) {
283  parseToLocation(Loc);
284 }
285 void ExpandModularHeadersPPCallbacks::Else(SourceLocation Loc, SourceLocation) {
286  parseToLocation(Loc);
287 }
288 void ExpandModularHeadersPPCallbacks::Endif(SourceLocation Loc,
289  SourceLocation) {
290  parseToLocation(Loc);
291 }
292 
293 } // namespace tooling
294 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
Some operations such as code completion produce a set of candidates.
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
bool IsAngled
true if this was an include with angle brackets
void checkAllFilesRecorded()
Makes sure we have contents for all the files we were interested in.
Preprocessor * getPreprocessor() const
Returns the preprocessor that provides callbacks for the whole translation unit, including the main f...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void recordFileContent(const FileEntry *File, const SrcMgr::ContentCache &ContentCache, llvm::vfs::InMemoryFileSystem &InMemoryFs)
Records content for a file and adds it to the FileSystem.
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
CharSourceRange Range
SourceRange for the file name.
ExpandModularHeadersPPCallbacks(CompilerInstance *Compiler, IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > OverlayFS)
void addNecessaryFile(const FileEntry *File)
Records that a given file entry is needed for replaying callbacks.