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 | : IndexCtx(std::move(IndexCtx)) {} |
32 | |
33 | void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, |
34 | SourceRange Range, const MacroArgs *Args) override { |
35 | IndexCtx->handleMacroReference(Name: *MacroNameTok.getIdentifierInfo(), |
36 | Loc: Range.getBegin(), MD: *MD.getMacroInfo()); |
37 | } |
38 | |
39 | void MacroDefined(const Token &MacroNameTok, |
40 | const MacroDirective *MD) override { |
41 | IndexCtx->handleMacroDefined(Name: *MacroNameTok.getIdentifierInfo(), |
42 | Loc: MacroNameTok.getLocation(), |
43 | MI: *MD->getMacroInfo()); |
44 | } |
45 | |
46 | void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, |
47 | const MacroDirective *Undef) override { |
48 | if (!MD.getMacroInfo()) // Ignore noop #undef. |
49 | return; |
50 | IndexCtx->handleMacroUndefined(Name: *MacroNameTok.getIdentifierInfo(), |
51 | Loc: MacroNameTok.getLocation(), |
52 | MI: *MD.getMacroInfo()); |
53 | } |
54 | |
55 | void Defined(const Token &MacroNameTok, const MacroDefinition &MD, |
56 | SourceRange Range) override { |
57 | if (!MD.getMacroInfo()) // Ignore nonexistent macro. |
58 | return; |
59 | // Note: this is defined(M), not #define M |
60 | IndexCtx->handleMacroReference(Name: *MacroNameTok.getIdentifierInfo(), |
61 | Loc: MacroNameTok.getLocation(), |
62 | MD: *MD.getMacroInfo()); |
63 | } |
64 | void Ifdef(SourceLocation Loc, const Token &MacroNameTok, |
65 | const MacroDefinition &MD) override { |
66 | if (!MD.getMacroInfo()) // Ignore non-existent macro. |
67 | return; |
68 | IndexCtx->handleMacroReference(Name: *MacroNameTok.getIdentifierInfo(), |
69 | Loc: MacroNameTok.getLocation(), |
70 | MD: *MD.getMacroInfo()); |
71 | } |
72 | void Ifndef(SourceLocation Loc, const Token &MacroNameTok, |
73 | const MacroDefinition &MD) override { |
74 | if (!MD.getMacroInfo()) // Ignore nonexistent macro. |
75 | return; |
76 | IndexCtx->handleMacroReference(Name: *MacroNameTok.getIdentifierInfo(), |
77 | Loc: MacroNameTok.getLocation(), |
78 | MD: *MD.getMacroInfo()); |
79 | } |
80 | |
81 | using PPCallbacks::Elifdef; |
82 | using PPCallbacks::Elifndef; |
83 | void Elifdef(SourceLocation Loc, const Token &MacroNameTok, |
84 | const MacroDefinition &MD) override { |
85 | if (!MD.getMacroInfo()) // Ignore non-existent macro. |
86 | return; |
87 | IndexCtx->handleMacroReference(Name: *MacroNameTok.getIdentifierInfo(), |
88 | Loc: MacroNameTok.getLocation(), |
89 | MD: *MD.getMacroInfo()); |
90 | } |
91 | void Elifndef(SourceLocation Loc, const Token &MacroNameTok, |
92 | const MacroDefinition &MD) override { |
93 | if (!MD.getMacroInfo()) // Ignore non-existent macro. |
94 | return; |
95 | IndexCtx->handleMacroReference(Name: *MacroNameTok.getIdentifierInfo(), |
96 | Loc: MacroNameTok.getLocation(), |
97 | MD: *MD.getMacroInfo()); |
98 | } |
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 | : DataConsumer(std::move(DataConsumer)), |
113 | IndexCtx(new IndexingContext(Opts, *this->DataConsumer)), |
114 | PP(std::move(PP)), |
115 | ShouldSkipFunctionBody(std::move(ShouldSkipFunctionBody)) { |
116 | assert(this->DataConsumer != nullptr); |
117 | assert(this->PP != nullptr); |
118 | } |
119 | |
120 | protected: |
121 | void Initialize(ASTContext &Context) override { |
122 | IndexCtx->setASTContext(Context); |
123 | IndexCtx->getDataConsumer().initialize(Ctx&: Context); |
124 | IndexCtx->getDataConsumer().setPreprocessor(PP); |
125 | PP->addPPCallbacks(C: std::make_unique<IndexPPCallbacks>(args&: IndexCtx)); |
126 | } |
127 | |
128 | bool HandleTopLevelDecl(DeclGroupRef DG) override { |
129 | return IndexCtx->indexDeclGroupRef(DG); |
130 | } |
131 | |
132 | void HandleInterestingDecl(DeclGroupRef DG) override { |
133 | // Ignore deserialized decls. |
134 | } |
135 | |
136 | void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { |
137 | IndexCtx->indexDeclGroupRef(DG); |
138 | } |
139 | |
140 | void HandleTranslationUnit(ASTContext &Ctx) override { |
141 | DataConsumer->finish(); |
142 | } |
143 | |
144 | bool shouldSkipFunctionBody(Decl *D) override { |
145 | return ShouldSkipFunctionBody(D); |
146 | } |
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 | : DataConsumer(std::move(DataConsumer)), Opts(Opts) { |
157 | assert(this->DataConsumer != nullptr); |
158 | } |
159 | |
160 | protected: |
161 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, |
162 | StringRef InFile) override { |
163 | return std::make_unique<IndexASTConsumer>( |
164 | args&: DataConsumer, args&: Opts, args: CI.getPreprocessorPtr(), |
165 | /*ShouldSkipFunctionBody=*/args: [](const Decl *) { return false; }); |
166 | } |
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 | std::function<bool(const Decl *)> ShouldSkipFunctionBody) { |
175 | return std::make_unique<IndexASTConsumer>(args&: DataConsumer, args: Opts, args&: PP, |
176 | args&: ShouldSkipFunctionBody); |
177 | } |
178 | |
179 | std::unique_ptr<ASTConsumer> clang::index::createIndexingASTConsumer( |
180 | std::shared_ptr<IndexDataConsumer> DataConsumer, |
181 | const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP) { |
182 | std::function<bool(const Decl *)> ShouldSkipFunctionBody = [](const Decl *) { |
183 | return false; |
184 | }; |
185 | if (Opts.ShouldTraverseDecl) |
186 | ShouldSkipFunctionBody = |
187 | [ShouldTraverseDecl(Opts.ShouldTraverseDecl)](const Decl *D) { |
188 | return !ShouldTraverseDecl(D); |
189 | }; |
190 | return createIndexingASTConsumer(DataConsumer: std::move(DataConsumer), Opts, PP: std::move(PP), |
191 | ShouldSkipFunctionBody: std::move(ShouldSkipFunctionBody)); |
192 | } |
193 | |
194 | std::unique_ptr<FrontendAction> |
195 | index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer, |
196 | const IndexingOptions &Opts) { |
197 | assert(DataConsumer != nullptr); |
198 | return std::make_unique<IndexAction>(args: std::move(DataConsumer), args: Opts); |
199 | } |
200 | |
201 | static bool topLevelDeclVisitor(void *context, const Decl *D) { |
202 | IndexingContext &IndexCtx = *static_cast<IndexingContext *>(context); |
203 | return IndexCtx.indexTopLevelDecl(D); |
204 | } |
205 | |
206 | static void (ASTUnit &Unit, IndexingContext &IndexCtx) { |
207 | Unit.visitLocalTopLevelDecls(context: &IndexCtx, Fn: topLevelDeclVisitor); |
208 | } |
209 | |
210 | static void indexPreprocessorMacro(const IdentifierInfo *II, |
211 | const MacroInfo *MI, |
212 | MacroDirective::Kind DirectiveKind, |
213 | SourceLocation Loc, |
214 | 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 | if (!MI) |
220 | return; |
221 | |
222 | // Skip implicit visibility change. |
223 | if (DirectiveKind == MacroDirective::MD_Visibility) |
224 | return; |
225 | |
226 | auto Role = DirectiveKind == MacroDirective::MD_Define |
227 | ? SymbolRole::Definition |
228 | : SymbolRole::Undefinition; |
229 | DataConsumer.handleMacroOccurrence(Name: II, MI, Roles: static_cast<unsigned>(Role), Loc); |
230 | } |
231 | |
232 | static void indexPreprocessorMacros(Preprocessor &PP, |
233 | IndexDataConsumer &DataConsumer) { |
234 | for (const auto &M : PP.macros()) { |
235 | for (auto *MD = M.second.getLatest(); MD; MD = MD->getPrevious()) { |
236 | indexPreprocessorMacro(II: M.first, MI: MD->getMacroInfo(), DirectiveKind: MD->getKind(), |
237 | Loc: MD->getLocation(), DataConsumer); |
238 | } |
239 | } |
240 | } |
241 | |
242 | static void indexPreprocessorModuleMacros(Preprocessor &PP, |
243 | serialization::ModuleFile &Mod, |
244 | IndexDataConsumer &DataConsumer) { |
245 | for (const auto &M : PP.macros()) { |
246 | if (M.second.getLatest() == nullptr) { |
247 | for (auto *MM : PP.getLeafModuleMacros(II: M.first)) { |
248 | auto *OwningMod = MM->getOwningModule(); |
249 | if (OwningMod && OwningMod->getASTFile() == Mod.File) { |
250 | if (auto *MI = MM->getMacroInfo()) { |
251 | indexPreprocessorMacro(II: M.first, MI, DirectiveKind: MacroDirective::MD_Define, |
252 | Loc: MI->getDefinitionLoc(), DataConsumer); |
253 | } |
254 | } |
255 | } |
256 | } |
257 | } |
258 | } |
259 | |
260 | void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, |
261 | IndexingOptions Opts) { |
262 | IndexingContext IndexCtx(Opts, DataConsumer); |
263 | IndexCtx.setASTContext(Unit.getASTContext()); |
264 | DataConsumer.initialize(Ctx&: Unit.getASTContext()); |
265 | DataConsumer.setPreprocessor(Unit.getPreprocessorPtr()); |
266 | |
267 | if (Opts.IndexMacrosInPreprocessor) |
268 | indexPreprocessorMacros(PP&: Unit.getPreprocessor(), DataConsumer); |
269 | indexTranslationUnit(Unit, IndexCtx); |
270 | DataConsumer.finish(); |
271 | } |
272 | |
273 | void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, |
274 | ArrayRef<const Decl *> Decls, |
275 | IndexDataConsumer &DataConsumer, |
276 | IndexingOptions Opts) { |
277 | IndexingContext IndexCtx(Opts, DataConsumer); |
278 | IndexCtx.setASTContext(Ctx); |
279 | |
280 | DataConsumer.initialize(Ctx); |
281 | |
282 | if (Opts.IndexMacrosInPreprocessor) |
283 | indexPreprocessorMacros(PP, DataConsumer); |
284 | |
285 | for (const Decl *D : Decls) |
286 | IndexCtx.indexTopLevelDecl(D); |
287 | DataConsumer.finish(); |
288 | } |
289 | |
290 | std::unique_ptr<PPCallbacks> |
291 | index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) { |
292 | return std::make_unique<IndexPPCallbacks>( |
293 | args: std::make_shared<IndexingContext>(args&: Opts, args&: Consumer)); |
294 | } |
295 | |
296 | void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, |
297 | IndexDataConsumer &DataConsumer, |
298 | IndexingOptions Opts) { |
299 | ASTContext &Ctx = Reader.getContext(); |
300 | IndexingContext IndexCtx(Opts, DataConsumer); |
301 | IndexCtx.setASTContext(Ctx); |
302 | DataConsumer.initialize(Ctx); |
303 | |
304 | if (Opts.IndexMacrosInPreprocessor) { |
305 | indexPreprocessorModuleMacros(PP&: Reader.getPreprocessor(), Mod, DataConsumer); |
306 | } |
307 | |
308 | for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { |
309 | IndexCtx.indexTopLevelDecl(D); |
310 | } |
311 | DataConsumer.finish(); |
312 | } |
313 | |