150
|
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
|
|
9 #include "ExpandModularHeadersPPCallbacks.h"
|
173
|
10 #include "clang/Basic/FileManager.h"
|
|
11 #include "clang/Basic/TargetInfo.h"
|
150
|
12 #include "clang/Frontend/CompilerInstance.h"
|
|
13 #include "clang/Lex/PreprocessorOptions.h"
|
|
14 #include "clang/Serialization/ASTReader.h"
|
252
|
15 #include <optional>
|
150
|
16
|
221
|
17 #define DEBUG_TYPE "clang-tidy"
|
|
18
|
252
|
19 namespace clang::tooling {
|
150
|
20
|
|
21 class ExpandModularHeadersPPCallbacks::FileRecorder {
|
|
22 public:
|
|
23 /// Records that a given file entry is needed for replaying callbacks.
|
221
|
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 }
|
150
|
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.
|
252
|
42 std::optional<StringRef> Data = ContentCache.getBufferDataIfLoaded();
|
221
|
43 if (!Data)
|
150
|
44 return;
|
|
45
|
|
46 InMemoryFs.addFile(File->getName(), /*ModificationTime=*/0,
|
221
|
47 llvm::MemoryBuffer::getMemBufferCopy(*Data));
|
150
|
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.
|
|
54 void checkAllFilesRecorded() {
|
221
|
55 LLVM_DEBUG({
|
|
56 for (auto FileEntry : FilesToRecord)
|
|
57 llvm::dbgs() << "Did not record contents for input file: "
|
|
58 << FileEntry->getName() << "\n";
|
|
59 });
|
150
|
60 }
|
|
61
|
|
62 private:
|
|
63 /// A set of files whose contents are to be recorded.
|
|
64 llvm::DenseSet<const FileEntry *> FilesToRecord;
|
|
65 };
|
|
66
|
|
67 ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
|
|
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);
|
252
|
82 // FIXME: Investigate whatever is there better way to initialize DiagEngine
|
|
83 // or whatever DiagEngine can be shared by multiple preprocessors
|
|
84 ProcessWarningOptions(Diags, Compiler.getDiagnosticOpts());
|
150
|
85
|
|
86 LangOpts.Modules = false;
|
|
87
|
|
88 auto HSO = std::make_shared<HeaderSearchOptions>();
|
|
89 *HSO = Compiler.getHeaderSearchOpts();
|
|
90
|
|
91 HeaderInfo = std::make_unique<HeaderSearch>(HSO, Sources, Diags, LangOpts,
|
|
92 &Compiler.getTarget());
|
|
93
|
|
94 auto PO = std::make_shared<PreprocessorOptions>();
|
|
95 *PO = Compiler.getPreprocessorOpts();
|
|
96
|
|
97 PP = std::make_unique<clang::Preprocessor>(PO, Diags, LangOpts, Sources,
|
|
98 *HeaderInfo, ModuleLoader,
|
|
99 /*IILookup=*/nullptr,
|
|
100 /*OwnsHeaderSearch=*/false);
|
|
101 PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
|
|
102 InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
|
|
103 Compiler.getFrontendOpts());
|
|
104 ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
|
|
105 Compiler.getTarget().getTriple());
|
|
106 }
|
|
107
|
|
108 ExpandModularHeadersPPCallbacks::~ExpandModularHeadersPPCallbacks() = default;
|
|
109
|
|
110 Preprocessor *ExpandModularHeadersPPCallbacks::getPreprocessor() const {
|
|
111 return PP.get();
|
|
112 }
|
|
113
|
|
114 void ExpandModularHeadersPPCallbacks::handleModuleFile(
|
|
115 serialization::ModuleFile *MF) {
|
|
116 if (!MF)
|
|
117 return;
|
|
118 // Avoid processing a ModuleFile more than once.
|
|
119 if (VisitedModules.count(MF))
|
|
120 return;
|
|
121 VisitedModules.insert(MF);
|
|
122
|
|
123 // Visit all the input files of this module and mark them to record their
|
|
124 // contents later.
|
|
125 Compiler.getASTReader()->visitInputFiles(
|
|
126 *MF, true, false,
|
|
127 [this](const serialization::InputFile &IF, bool /*IsSystem*/) {
|
|
128 Recorder->addNecessaryFile(IF.getFile());
|
|
129 });
|
|
130 // Recursively handle all transitively imported modules.
|
221
|
131 for (auto *Import : MF->Imports)
|
150
|
132 handleModuleFile(Import);
|
|
133 }
|
|
134
|
|
135 void ExpandModularHeadersPPCallbacks::parseToLocation(SourceLocation Loc) {
|
|
136 // Load all source locations present in the external sources.
|
|
137 for (unsigned I = 0, N = Sources.loaded_sloc_entry_size(); I != N; ++I) {
|
|
138 Sources.getLoadedSLocEntry(I, nullptr);
|
|
139 }
|
|
140 // Record contents of files we are interested in and add to the FileSystem.
|
|
141 for (auto It = Sources.fileinfo_begin(); It != Sources.fileinfo_end(); ++It) {
|
|
142 Recorder->recordFileContent(It->getFirst(), *It->getSecond(), *InMemoryFs);
|
|
143 }
|
|
144 Recorder->checkAllFilesRecorded();
|
|
145
|
|
146 if (!StartedLexing) {
|
|
147 StartedLexing = true;
|
|
148 PP->Lex(CurrentToken);
|
|
149 }
|
|
150 while (!CurrentToken.is(tok::eof) &&
|
|
151 Sources.isBeforeInTranslationUnit(CurrentToken.getLocation(), Loc)) {
|
|
152 PP->Lex(CurrentToken);
|
|
153 }
|
|
154 }
|
|
155
|
|
156 void ExpandModularHeadersPPCallbacks::FileChanged(
|
|
157 SourceLocation Loc, FileChangeReason Reason,
|
|
158 SrcMgr::CharacteristicKind FileType, FileID PrevFID = FileID()) {
|
|
159 if (!EnteredMainFile) {
|
|
160 EnteredMainFile = true;
|
|
161 PP->EnterMainSourceFile();
|
|
162 }
|
|
163 }
|
|
164
|
|
165 void ExpandModularHeadersPPCallbacks::InclusionDirective(
|
|
166 SourceLocation DirectiveLoc, const Token &IncludeToken,
|
|
167 StringRef IncludedFilename, bool IsAngled, CharSourceRange FilenameRange,
|
252
|
168 OptionalFileEntryRef IncludedFile, StringRef SearchPath,
|
236
|
169 StringRef RelativePath, const Module *Imported,
|
|
170 SrcMgr::CharacteristicKind FileType) {
|
150
|
171 if (Imported) {
|
|
172 serialization::ModuleFile *MF =
|
|
173 Compiler.getASTReader()->getModuleManager().lookup(
|
|
174 Imported->getASTFile());
|
|
175 handleModuleFile(MF);
|
|
176 }
|
|
177 parseToLocation(DirectiveLoc);
|
|
178 }
|
|
179
|
|
180 void ExpandModularHeadersPPCallbacks::EndOfMainFile() {
|
|
181 while (!CurrentToken.is(tok::eof))
|
|
182 PP->Lex(CurrentToken);
|
|
183 }
|
|
184
|
|
185 // Handle all other callbacks.
|
|
186 // Just parse to the corresponding location to generate the same callback for
|
|
187 // the PPCallbacks registered in our custom preprocessor.
|
|
188 void ExpandModularHeadersPPCallbacks::Ident(SourceLocation Loc, StringRef) {
|
|
189 parseToLocation(Loc);
|
|
190 }
|
|
191 void ExpandModularHeadersPPCallbacks::PragmaDirective(SourceLocation Loc,
|
|
192 PragmaIntroducerKind) {
|
|
193 parseToLocation(Loc);
|
|
194 }
|
|
195 void ExpandModularHeadersPPCallbacks::PragmaComment(SourceLocation Loc,
|
|
196 const IdentifierInfo *,
|
|
197 StringRef) {
|
|
198 parseToLocation(Loc);
|
|
199 }
|
|
200 void ExpandModularHeadersPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
|
|
201 StringRef,
|
|
202 StringRef) {
|
|
203 parseToLocation(Loc);
|
|
204 }
|
|
205 void ExpandModularHeadersPPCallbacks::PragmaDebug(SourceLocation Loc,
|
|
206 StringRef) {
|
|
207 parseToLocation(Loc);
|
|
208 }
|
|
209 void ExpandModularHeadersPPCallbacks::PragmaMessage(SourceLocation Loc,
|
|
210 StringRef,
|
|
211 PragmaMessageKind,
|
|
212 StringRef) {
|
|
213 parseToLocation(Loc);
|
|
214 }
|
|
215 void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPush(SourceLocation Loc,
|
|
216 StringRef) {
|
|
217 parseToLocation(Loc);
|
|
218 }
|
|
219 void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPop(SourceLocation Loc,
|
|
220 StringRef) {
|
|
221 parseToLocation(Loc);
|
|
222 }
|
|
223 void ExpandModularHeadersPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
|
|
224 StringRef,
|
|
225 diag::Severity,
|
|
226 StringRef) {
|
|
227 parseToLocation(Loc);
|
|
228 }
|
|
229 void ExpandModularHeadersPPCallbacks::HasInclude(SourceLocation Loc, StringRef,
|
252
|
230 bool, OptionalFileEntryRef,
|
150
|
231 SrcMgr::CharacteristicKind) {
|
|
232 parseToLocation(Loc);
|
|
233 }
|
|
234 void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
|
|
235 SourceLocation NameLoc, const IdentifierInfo *, SourceLocation StateLoc,
|
|
236 unsigned) {
|
221
|
237 // FIXME: Figure out whether it's the right location to parse to.
|
150
|
238 parseToLocation(NameLoc);
|
|
239 }
|
|
240 void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc,
|
236
|
241 PragmaWarningSpecifier,
|
|
242 ArrayRef<int>) {
|
150
|
243 parseToLocation(Loc);
|
|
244 }
|
|
245 void ExpandModularHeadersPPCallbacks::PragmaWarningPush(SourceLocation Loc,
|
|
246 int) {
|
|
247 parseToLocation(Loc);
|
|
248 }
|
|
249 void ExpandModularHeadersPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
|
|
250 parseToLocation(Loc);
|
|
251 }
|
|
252 void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullBegin(
|
|
253 SourceLocation Loc) {
|
|
254 parseToLocation(Loc);
|
|
255 }
|
|
256 void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullEnd(
|
|
257 SourceLocation Loc) {
|
|
258 parseToLocation(Loc);
|
|
259 }
|
|
260 void ExpandModularHeadersPPCallbacks::MacroExpands(const Token &MacroNameTok,
|
|
261 const MacroDefinition &,
|
|
262 SourceRange Range,
|
|
263 const MacroArgs *) {
|
221
|
264 // FIXME: Figure out whether it's the right location to parse to.
|
150
|
265 parseToLocation(Range.getBegin());
|
|
266 }
|
|
267 void ExpandModularHeadersPPCallbacks::MacroDefined(const Token &MacroNameTok,
|
|
268 const MacroDirective *MD) {
|
|
269 parseToLocation(MD->getLocation());
|
|
270 }
|
|
271 void ExpandModularHeadersPPCallbacks::MacroUndefined(
|
|
272 const Token &, const MacroDefinition &, const MacroDirective *Undef) {
|
|
273 if (Undef)
|
|
274 parseToLocation(Undef->getLocation());
|
|
275 }
|
|
276 void ExpandModularHeadersPPCallbacks::Defined(const Token &MacroNameTok,
|
|
277 const MacroDefinition &,
|
|
278 SourceRange Range) {
|
221
|
279 // FIXME: Figure out whether it's the right location to parse to.
|
150
|
280 parseToLocation(Range.getBegin());
|
|
281 }
|
|
282 void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
|
|
283 SourceRange Range, SourceLocation EndifLoc) {
|
221
|
284 // FIXME: Figure out whether it's the right location to parse to.
|
150
|
285 parseToLocation(EndifLoc);
|
|
286 }
|
|
287 void ExpandModularHeadersPPCallbacks::If(SourceLocation Loc, SourceRange,
|
|
288 ConditionValueKind) {
|
|
289 parseToLocation(Loc);
|
|
290 }
|
|
291 void ExpandModularHeadersPPCallbacks::Elif(SourceLocation Loc, SourceRange,
|
|
292 ConditionValueKind, SourceLocation) {
|
|
293 parseToLocation(Loc);
|
|
294 }
|
|
295 void ExpandModularHeadersPPCallbacks::Ifdef(SourceLocation Loc, const Token &,
|
|
296 const MacroDefinition &) {
|
|
297 parseToLocation(Loc);
|
|
298 }
|
|
299 void ExpandModularHeadersPPCallbacks::Ifndef(SourceLocation Loc, const Token &,
|
|
300 const MacroDefinition &) {
|
|
301 parseToLocation(Loc);
|
|
302 }
|
|
303 void ExpandModularHeadersPPCallbacks::Else(SourceLocation Loc, SourceLocation) {
|
|
304 parseToLocation(Loc);
|
|
305 }
|
|
306 void ExpandModularHeadersPPCallbacks::Endif(SourceLocation Loc,
|
|
307 SourceLocation) {
|
|
308 parseToLocation(Loc);
|
|
309 }
|
|
310
|
252
|
311 } // namespace clang::tooling
|