/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Index/IndexingAction.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- IndexingAction.cpp - Frontend index action -------------------------===// |
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 "clang/Index/IndexingAction.h" |
10 | | #include "IndexingContext.h" |
11 | | #include "clang/Frontend/CompilerInstance.h" |
12 | | #include "clang/Frontend/FrontendAction.h" |
13 | | #include "clang/Frontend/MultiplexConsumer.h" |
14 | | #include "clang/Index/IndexDataConsumer.h" |
15 | | #include "clang/Lex/PPCallbacks.h" |
16 | | #include "clang/Lex/Preprocessor.h" |
17 | | #include "clang/Serialization/ASTReader.h" |
18 | | #include "llvm/ADT/STLExtras.h" |
19 | | #include <memory> |
20 | | |
21 | | using namespace clang; |
22 | | using namespace clang::index; |
23 | | |
24 | | namespace { |
25 | | |
26 | | class IndexPPCallbacks final : public PPCallbacks { |
27 | | std::shared_ptr<IndexingContext> IndexCtx; |
28 | | |
29 | | public: |
30 | | IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx) |
31 | 95 | : IndexCtx(std::move(IndexCtx)) {} |
32 | | |
33 | | void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, |
34 | 148 | SourceRange Range, const MacroArgs *Args) override { |
35 | 148 | IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), |
36 | 148 | Range.getBegin(), *MD.getMacroInfo()); |
37 | 148 | } |
38 | | |
39 | | void MacroDefined(const Token &MacroNameTok, |
40 | 39.4k | const MacroDirective *MD) override { |
41 | 39.4k | IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(), |
42 | 39.4k | MacroNameTok.getLocation(), |
43 | 39.4k | *MD->getMacroInfo()); |
44 | 39.4k | } |
45 | | |
46 | | void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, |
47 | 8 | const MacroDirective *Undef) override { |
48 | 8 | if (!MD.getMacroInfo()) // Ignore noop #undef. |
49 | 0 | return; |
50 | 8 | IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(), |
51 | 8 | MacroNameTok.getLocation(), |
52 | 8 | *MD.getMacroInfo()); |
53 | 8 | } |
54 | | |
55 | | void Defined(const Token &MacroNameTok, const MacroDefinition &MD, |
56 | 34 | SourceRange Range) override { |
57 | 34 | if (!MD.getMacroInfo()) // Ignore nonexistent macro. |
58 | 11 | return; |
59 | | // Note: this is defined(M), not #define M |
60 | 23 | IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), |
61 | 23 | MacroNameTok.getLocation(), |
62 | 23 | *MD.getMacroInfo()); |
63 | 23 | } |
64 | | void Ifdef(SourceLocation Loc, const Token &MacroNameTok, |
65 | 24 | const MacroDefinition &MD) override { |
66 | 24 | if (!MD.getMacroInfo()) // Ignore non-existent macro. |
67 | 5 | return; |
68 | 19 | IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), |
69 | 19 | MacroNameTok.getLocation(), |
70 | 19 | *MD.getMacroInfo()); |
71 | 19 | } |
72 | | void Ifndef(SourceLocation Loc, const Token &MacroNameTok, |
73 | 19 | const MacroDefinition &MD) override { |
74 | 19 | if (!MD.getMacroInfo()) // Ignore nonexistent macro. |
75 | 11 | return; |
76 | 8 | IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), |
77 | 8 | MacroNameTok.getLocation(), |
78 | 8 | *MD.getMacroInfo()); |
79 | 8 | } |
80 | | |
81 | | using PPCallbacks::Elifdef; |
82 | | using PPCallbacks::Elifndef; |
83 | | void Elifdef(SourceLocation Loc, const Token &MacroNameTok, |
84 | 0 | const MacroDefinition &MD) override { |
85 | 0 | if (!MD.getMacroInfo()) // Ignore non-existent macro. |
86 | 0 | return; |
87 | 0 | IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), |
88 | 0 | MacroNameTok.getLocation(), |
89 | 0 | *MD.getMacroInfo()); |
90 | 0 | } |
91 | | void Elifndef(SourceLocation Loc, const Token &MacroNameTok, |
92 | 0 | const MacroDefinition &MD) override { |
93 | 0 | if (!MD.getMacroInfo()) // Ignore non-existent macro. |
94 | 0 | return; |
95 | 0 | IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), |
96 | 0 | MacroNameTok.getLocation(), |
97 | 0 | *MD.getMacroInfo()); |
98 | 0 | } |
99 | | }; |
100 | | |
101 | | class IndexASTConsumer final : public ASTConsumer { |
102 | | std::shared_ptr<IndexDataConsumer> DataConsumer; |
103 | | std::shared_ptr<IndexingContext> IndexCtx; |
104 | | std::shared_ptr<Preprocessor> PP; |
105 | | std::function<bool(const Decl *)> ShouldSkipFunctionBody; |
106 | | |
107 | | public: |
108 | | IndexASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer, |
109 | | const IndexingOptions &Opts, |
110 | | std::shared_ptr<Preprocessor> PP, |
111 | | std::function<bool(const Decl *)> ShouldSkipFunctionBody) |
112 | 70 | : DataConsumer(std::move(DataConsumer)), |
113 | 70 | IndexCtx(new IndexingContext(Opts, *this->DataConsumer)), |
114 | 70 | PP(std::move(PP)), |
115 | 70 | ShouldSkipFunctionBody(std::move(ShouldSkipFunctionBody)) { |
116 | 70 | assert(this->DataConsumer != nullptr); |
117 | 70 | assert(this->PP != nullptr); |
118 | 70 | } |
119 | | |
120 | | protected: |
121 | 95 | void Initialize(ASTContext &Context) override { |
122 | 95 | IndexCtx->setASTContext(Context); |
123 | 95 | IndexCtx->getDataConsumer().initialize(Context); |
124 | 95 | IndexCtx->getDataConsumer().setPreprocessor(PP); |
125 | 95 | PP->addPPCallbacks(std::make_unique<IndexPPCallbacks>(IndexCtx)); |
126 | 95 | } |
127 | | |
128 | 633 | bool HandleTopLevelDecl(DeclGroupRef DG) override { |
129 | 633 | return IndexCtx->indexDeclGroupRef(DG); |
130 | 633 | } |
131 | | |
132 | 7 | void HandleInterestingDecl(DeclGroupRef DG) override { |
133 | | // Ignore deserialized decls. |
134 | 7 | } |
135 | | |
136 | 1 | void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { |
137 | 1 | IndexCtx->indexDeclGroupRef(DG); |
138 | 1 | } |
139 | | |
140 | 70 | void HandleTranslationUnit(ASTContext &Ctx) override { |
141 | 70 | DataConsumer->finish(); |
142 | 70 | } |
143 | | |
144 | 39 | bool shouldSkipFunctionBody(Decl *D) override { |
145 | 39 | return ShouldSkipFunctionBody(D); |
146 | 39 | } |
147 | | }; |
148 | | |
149 | | class IndexAction final : public ASTFrontendAction { |
150 | | std::shared_ptr<IndexDataConsumer> DataConsumer; |
151 | | IndexingOptions Opts; |
152 | | |
153 | | public: |
154 | | IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer, |
155 | | const IndexingOptions &Opts) |
156 | 25 | : DataConsumer(std::move(DataConsumer)), Opts(Opts) { |
157 | 25 | assert(this->DataConsumer != nullptr); |
158 | 25 | } |
159 | | |
160 | | protected: |
161 | | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, |
162 | 25 | StringRef InFile) override { |
163 | 25 | return std::make_unique<IndexASTConsumer>( |
164 | 25 | DataConsumer, Opts, CI.getPreprocessorPtr(), |
165 | 25 | /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; }0 ); |
166 | 25 | } |
167 | | }; |
168 | | |
169 | | } // anonymous namespace |
170 | | |
171 | | std::unique_ptr<ASTConsumer> index::createIndexingASTConsumer( |
172 | | std::shared_ptr<IndexDataConsumer> DataConsumer, |
173 | | const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP, |
174 | 45 | std::function<bool(const Decl *)> ShouldSkipFunctionBody) { |
175 | 45 | return std::make_unique<IndexASTConsumer>(DataConsumer, Opts, PP, |
176 | 45 | ShouldSkipFunctionBody); |
177 | 45 | } |
178 | | |
179 | | std::unique_ptr<ASTConsumer> clang::index::createIndexingASTConsumer( |
180 | | std::shared_ptr<IndexDataConsumer> DataConsumer, |
181 | 0 | const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP) { |
182 | 0 | std::function<bool(const Decl *)> ShouldSkipFunctionBody = [](const Decl *) { |
183 | 0 | return false; |
184 | 0 | }; |
185 | 0 | if (Opts.ShouldTraverseDecl) |
186 | 0 | ShouldSkipFunctionBody = |
187 | 0 | [ShouldTraverseDecl(Opts.ShouldTraverseDecl)](const Decl *D) { |
188 | 0 | return !ShouldTraverseDecl(D); |
189 | 0 | }; |
190 | 0 | return createIndexingASTConsumer(std::move(DataConsumer), Opts, std::move(PP), |
191 | 0 | std::move(ShouldSkipFunctionBody)); |
192 | 0 | } |
193 | | |
194 | | std::unique_ptr<FrontendAction> |
195 | | index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer, |
196 | 25 | const IndexingOptions &Opts) { |
197 | 25 | assert(DataConsumer != nullptr); |
198 | 25 | return std::make_unique<IndexAction>(std::move(DataConsumer), Opts); |
199 | 25 | } |
200 | | |
201 | 66 | static bool topLevelDeclVisitor(void *context, const Decl *D) { |
202 | 66 | IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context); |
203 | 66 | return IndexCtx.indexTopLevelDecl(D); |
204 | 66 | } |
205 | | |
206 | 11 | static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) { |
207 | 11 | Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor); |
208 | 11 | } |
209 | | |
210 | | static void indexPreprocessorMacro(const IdentifierInfo *II, |
211 | | const MacroInfo *MI, |
212 | | MacroDirective::Kind DirectiveKind, |
213 | | SourceLocation Loc, |
214 | 493 | IndexDataConsumer &DataConsumer) { |
215 | | // When using modules, it may happen that we find #undef of a macro that |
216 | | // was defined in another module. In such case, MI may be nullptr, since |
217 | | // we only look for macro definitions in the current TU. In that case, |
218 | | // there is nothing to index. |
219 | 493 | if (!MI) |
220 | 0 | return; |
221 | | |
222 | | // Skip implicit visibility change. |
223 | 493 | if (DirectiveKind == MacroDirective::MD_Visibility) |
224 | 0 | return; |
225 | | |
226 | 493 | auto Role = DirectiveKind == MacroDirective::MD_Define |
227 | 493 | ? SymbolRole::Definition491 |
228 | 493 | : SymbolRole::Undefinition2 ; |
229 | 493 | DataConsumer.handleMacroOccurrence(II, MI, static_cast<unsigned>(Role), Loc); |
230 | 493 | } |
231 | | |
232 | | static void indexPreprocessorMacros(Preprocessor &PP, |
233 | 1 | IndexDataConsumer &DataConsumer) { |
234 | 488 | for (const auto &M : PP.macros()) { |
235 | 979 | for (auto *MD = M.second.getLatest(); MD; MD = MD->getPrevious()491 ) { |
236 | 491 | indexPreprocessorMacro(M.first, MD->getMacroInfo(), MD->getKind(), |
237 | 491 | MD->getLocation(), DataConsumer); |
238 | 491 | } |
239 | 488 | } |
240 | 1 | } |
241 | | |
242 | | static void indexPreprocessorModuleMacros(Preprocessor &PP, |
243 | | serialization::ModuleFile &Mod, |
244 | 1 | IndexDataConsumer &DataConsumer) { |
245 | 436 | for (const auto &M : PP.macros()) { |
246 | 436 | if (M.second.getLatest() == nullptr) { |
247 | 2 | for (auto *MM : PP.getLeafModuleMacros(M.first)) { |
248 | 2 | auto *OwningMod = MM->getOwningModule(); |
249 | 2 | if (OwningMod && OwningMod->getASTFile() == Mod.File) { |
250 | 2 | if (auto *MI = MM->getMacroInfo()) { |
251 | 2 | indexPreprocessorMacro(M.first, MI, MacroDirective::MD_Define, |
252 | 2 | MI->getDefinitionLoc(), DataConsumer); |
253 | 2 | } |
254 | 2 | } |
255 | 2 | } |
256 | 2 | } |
257 | 436 | } |
258 | 1 | } |
259 | | |
260 | | void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, |
261 | 11 | IndexingOptions Opts) { |
262 | 11 | IndexingContext IndexCtx(Opts, DataConsumer); |
263 | 11 | IndexCtx.setASTContext(Unit.getASTContext()); |
264 | 11 | DataConsumer.initialize(Unit.getASTContext()); |
265 | 11 | DataConsumer.setPreprocessor(Unit.getPreprocessorPtr()); |
266 | | |
267 | 11 | if (Opts.IndexMacrosInPreprocessor) |
268 | 0 | indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer); |
269 | 11 | indexTranslationUnit(Unit, IndexCtx); |
270 | 11 | DataConsumer.finish(); |
271 | 11 | } |
272 | | |
273 | | void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, |
274 | | ArrayRef<const Decl *> Decls, |
275 | | IndexDataConsumer &DataConsumer, |
276 | 18 | IndexingOptions Opts) { |
277 | 18 | IndexingContext IndexCtx(Opts, DataConsumer); |
278 | 18 | IndexCtx.setASTContext(Ctx); |
279 | | |
280 | 18 | DataConsumer.initialize(Ctx); |
281 | | |
282 | 18 | if (Opts.IndexMacrosInPreprocessor) |
283 | 1 | indexPreprocessorMacros(PP, DataConsumer); |
284 | | |
285 | 18 | for (const Decl *D : Decls) |
286 | 118 | IndexCtx.indexTopLevelDecl(D); |
287 | 18 | DataConsumer.finish(); |
288 | 18 | } |
289 | | |
290 | | std::unique_ptr<PPCallbacks> |
291 | 0 | index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) { |
292 | 0 | return std::make_unique<IndexPPCallbacks>( |
293 | 0 | std::make_shared<IndexingContext>(Opts, Consumer)); |
294 | 0 | } |
295 | | |
296 | | void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, |
297 | | IndexDataConsumer &DataConsumer, |
298 | 1 | IndexingOptions Opts) { |
299 | 1 | ASTContext &Ctx = Reader.getContext(); |
300 | 1 | IndexingContext IndexCtx(Opts, DataConsumer); |
301 | 1 | IndexCtx.setASTContext(Ctx); |
302 | 1 | DataConsumer.initialize(Ctx); |
303 | | |
304 | 1 | if (Opts.IndexMacrosInPreprocessor) { |
305 | 1 | indexPreprocessorModuleMacros(Reader.getPreprocessor(), Mod, DataConsumer); |
306 | 1 | } |
307 | | |
308 | 6 | for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { |
309 | 6 | IndexCtx.indexTopLevelDecl(D); |
310 | 6 | } |
311 | 1 | DataConsumer.finish(); |
312 | 1 | } |