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