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