1 //===- ExpandModularHeadersPPCallbacks.h - clang-tidy -----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ExpandModularHeadersPPCallbacks.h"
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"
17 #define DEBUG_TYPE "clang-tidy"
19 namespace clang::tooling
{
21 class ExpandModularHeadersPPCallbacks::FileRecorder
{
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().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
);
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
.count(File
))
41 // FIXME: Why is this happening? We might be losing contents here.
42 std::optional
<StringRef
> Data
= ContentCache
.getBufferDataIfLoaded();
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
);
52 /// Makes sure we have contents for all the files we were interested in. Ideally
53 /// `FilesToRecord` should be empty.
54 void checkAllFilesRecorded() {
56 for (auto FileEntry
: FilesToRecord
)
57 llvm::dbgs() << "Did not record contents for input file: "
58 << FileEntry
.getName() << "\n";
63 /// A set of files whose contents are to be recorded.
64 llvm::DenseSet
<FileEntryRef
> FilesToRecord
;
67 ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
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
79 OverlayFS
->pushOverlay(InMemoryFs
);
81 Diags
.setSourceManager(&Sources
);
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());
86 LangOpts
.Modules
= false;
88 auto HSO
= std::make_shared
<HeaderSearchOptions
>();
89 *HSO
= Compiler
.getHeaderSearchOpts();
91 HeaderInfo
= std::make_unique
<HeaderSearch
>(HSO
, Sources
, Diags
, LangOpts
,
92 &Compiler
.getTarget());
94 auto PO
= std::make_shared
<PreprocessorOptions
>();
95 *PO
= Compiler
.getPreprocessorOpts();
97 PP
= std::make_unique
<clang::Preprocessor
>(PO
, Diags
, LangOpts
, Sources
,
98 *HeaderInfo
, ModuleLoader
,
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());
108 ExpandModularHeadersPPCallbacks::~ExpandModularHeadersPPCallbacks() = default;
110 Preprocessor
*ExpandModularHeadersPPCallbacks::getPreprocessor() const {
114 void ExpandModularHeadersPPCallbacks::handleModuleFile(
115 serialization::ModuleFile
*MF
) {
118 // Avoid processing a ModuleFile more than once.
119 if (VisitedModules
.count(MF
))
121 VisitedModules
.insert(MF
);
123 // Visit all the input files of this module and mark them to record their
125 Compiler
.getASTReader()->visitInputFiles(
127 [this](const serialization::InputFile
&IF
, bool /*IsSystem*/) {
128 Recorder
->addNecessaryFile(*IF
.getFile());
130 // Recursively handle all transitively imported modules.
131 for (auto *Import
: MF
->Imports
)
132 handleModuleFile(Import
);
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);
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
);
144 Recorder
->checkAllFilesRecorded();
146 if (!StartedLexing
) {
147 StartedLexing
= true;
148 PP
->Lex(CurrentToken
);
150 while (!CurrentToken
.is(tok::eof
) &&
151 Sources
.isBeforeInTranslationUnit(CurrentToken
.getLocation(), Loc
)) {
152 PP
->Lex(CurrentToken
);
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();
165 void ExpandModularHeadersPPCallbacks::InclusionDirective(
166 SourceLocation DirectiveLoc
, const Token
&IncludeToken
,
167 StringRef IncludedFilename
, bool IsAngled
, CharSourceRange FilenameRange
,
168 OptionalFileEntryRef IncludedFile
, StringRef SearchPath
,
169 StringRef RelativePath
, const Module
*Imported
,
170 SrcMgr::CharacteristicKind FileType
) {
172 serialization::ModuleFile
*MF
=
173 Compiler
.getASTReader()->getModuleManager().lookup(
174 Imported
->getASTFile());
175 handleModuleFile(MF
);
177 parseToLocation(DirectiveLoc
);
180 void ExpandModularHeadersPPCallbacks::EndOfMainFile() {
181 while (!CurrentToken
.is(tok::eof
))
182 PP
->Lex(CurrentToken
);
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
);
191 void ExpandModularHeadersPPCallbacks::PragmaDirective(SourceLocation Loc
,
192 PragmaIntroducerKind
) {
193 parseToLocation(Loc
);
195 void ExpandModularHeadersPPCallbacks::PragmaComment(SourceLocation Loc
,
196 const IdentifierInfo
*,
198 parseToLocation(Loc
);
200 void ExpandModularHeadersPPCallbacks::PragmaDetectMismatch(SourceLocation Loc
,
203 parseToLocation(Loc
);
205 void ExpandModularHeadersPPCallbacks::PragmaDebug(SourceLocation Loc
,
207 parseToLocation(Loc
);
209 void ExpandModularHeadersPPCallbacks::PragmaMessage(SourceLocation Loc
,
213 parseToLocation(Loc
);
215 void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPush(SourceLocation Loc
,
217 parseToLocation(Loc
);
219 void ExpandModularHeadersPPCallbacks::PragmaDiagnosticPop(SourceLocation Loc
,
221 parseToLocation(Loc
);
223 void ExpandModularHeadersPPCallbacks::PragmaDiagnostic(SourceLocation Loc
,
227 parseToLocation(Loc
);
229 void ExpandModularHeadersPPCallbacks::HasInclude(SourceLocation Loc
, StringRef
,
230 bool, OptionalFileEntryRef
,
231 SrcMgr::CharacteristicKind
) {
232 parseToLocation(Loc
);
234 void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
235 SourceLocation NameLoc
, const IdentifierInfo
*, SourceLocation StateLoc
,
237 // FIXME: Figure out whether it's the right location to parse to.
238 parseToLocation(NameLoc
);
240 void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc
,
241 PragmaWarningSpecifier
,
243 parseToLocation(Loc
);
245 void ExpandModularHeadersPPCallbacks::PragmaWarningPush(SourceLocation Loc
,
247 parseToLocation(Loc
);
249 void ExpandModularHeadersPPCallbacks::PragmaWarningPop(SourceLocation Loc
) {
250 parseToLocation(Loc
);
252 void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullBegin(
253 SourceLocation Loc
) {
254 parseToLocation(Loc
);
256 void ExpandModularHeadersPPCallbacks::PragmaAssumeNonNullEnd(
257 SourceLocation Loc
) {
258 parseToLocation(Loc
);
260 void ExpandModularHeadersPPCallbacks::MacroExpands(const Token
&MacroNameTok
,
261 const MacroDefinition
&,
264 // FIXME: Figure out whether it's the right location to parse to.
265 parseToLocation(Range
.getBegin());
267 void ExpandModularHeadersPPCallbacks::MacroDefined(const Token
&MacroNameTok
,
268 const MacroDirective
*MD
) {
269 parseToLocation(MD
->getLocation());
271 void ExpandModularHeadersPPCallbacks::MacroUndefined(
272 const Token
&, const MacroDefinition
&, const MacroDirective
*Undef
) {
274 parseToLocation(Undef
->getLocation());
276 void ExpandModularHeadersPPCallbacks::Defined(const Token
&MacroNameTok
,
277 const MacroDefinition
&,
279 // FIXME: Figure out whether it's the right location to parse to.
280 parseToLocation(Range
.getBegin());
282 void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
283 SourceRange Range
, SourceLocation EndifLoc
) {
284 // FIXME: Figure out whether it's the right location to parse to.
285 parseToLocation(EndifLoc
);
287 void ExpandModularHeadersPPCallbacks::If(SourceLocation Loc
, SourceRange
,
288 ConditionValueKind
) {
289 parseToLocation(Loc
);
291 void ExpandModularHeadersPPCallbacks::Elif(SourceLocation Loc
, SourceRange
,
292 ConditionValueKind
, SourceLocation
) {
293 parseToLocation(Loc
);
295 void ExpandModularHeadersPPCallbacks::Ifdef(SourceLocation Loc
, const Token
&,
296 const MacroDefinition
&) {
297 parseToLocation(Loc
);
299 void ExpandModularHeadersPPCallbacks::Ifndef(SourceLocation Loc
, const Token
&,
300 const MacroDefinition
&) {
301 parseToLocation(Loc
);
303 void ExpandModularHeadersPPCallbacks::Else(SourceLocation Loc
, SourceLocation
) {
304 parseToLocation(Loc
);
306 void ExpandModularHeadersPPCallbacks::Endif(SourceLocation Loc
,
308 parseToLocation(Loc
);
311 } // namespace clang::tooling