clang-tools 10.0.0

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