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