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