1 //===- IndexingAction.cpp - Frontend index action -------------------------===//
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 "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"
21 using namespace clang;
22 using namespace clang::index;
24 bool IndexDataConsumer::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
25 ArrayRef<SymbolRelation> Relations,
27 ASTNodeInfo ASTNode) {
31 bool IndexDataConsumer::handleMacroOccurence(const IdentifierInfo *Name,
38 bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD,
47 class IndexASTConsumer : public ASTConsumer {
48 std::shared_ptr<Preprocessor> PP;
49 std::shared_ptr<IndexingContext> IndexCtx;
52 IndexASTConsumer(std::shared_ptr<Preprocessor> PP,
53 std::shared_ptr<IndexingContext> IndexCtx)
54 : PP(std::move(PP)), IndexCtx(std::move(IndexCtx)) {}
57 void Initialize(ASTContext &Context) override {
58 IndexCtx->setASTContext(Context);
59 IndexCtx->getDataConsumer().initialize(Context);
60 IndexCtx->getDataConsumer().setPreprocessor(PP);
63 bool HandleTopLevelDecl(DeclGroupRef DG) override {
64 return IndexCtx->indexDeclGroupRef(DG);
67 void HandleInterestingDecl(DeclGroupRef DG) override {
68 // Ignore deserialized decls.
71 void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
72 IndexCtx->indexDeclGroupRef(DG);
75 void HandleTranslationUnit(ASTContext &Ctx) override {
79 class IndexPPCallbacks : public PPCallbacks {
80 std::shared_ptr<IndexingContext> IndexCtx;
83 IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx)
84 : IndexCtx(std::move(IndexCtx)) {}
86 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
87 SourceRange Range, const MacroArgs *Args) override {
88 IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
89 Range.getBegin(), *MD.getMacroInfo());
92 void MacroDefined(const Token &MacroNameTok,
93 const MacroDirective *MD) override {
94 IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(),
95 MacroNameTok.getLocation(),
99 void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
100 const MacroDirective *Undef) override {
101 if (!MD.getMacroInfo()) // Ignore noop #undef.
103 IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(),
104 MacroNameTok.getLocation(),
109 class IndexActionBase {
111 std::shared_ptr<IndexDataConsumer> DataConsumer;
112 std::shared_ptr<IndexingContext> IndexCtx;
114 IndexActionBase(std::shared_ptr<IndexDataConsumer> dataConsumer,
115 IndexingOptions Opts)
116 : DataConsumer(std::move(dataConsumer)),
117 IndexCtx(new IndexingContext(Opts, *DataConsumer)) {}
119 std::unique_ptr<IndexASTConsumer>
120 createIndexASTConsumer(CompilerInstance &CI) {
121 return llvm::make_unique<IndexASTConsumer>(CI.getPreprocessorPtr(),
125 std::unique_ptr<PPCallbacks> createIndexPPCallbacks() {
126 return llvm::make_unique<IndexPPCallbacks>(IndexCtx);
130 DataConsumer->finish();
134 class IndexAction : public ASTFrontendAction, IndexActionBase {
136 IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
137 IndexingOptions Opts)
138 : IndexActionBase(std::move(DataConsumer), Opts) {}
141 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
142 StringRef InFile) override {
143 return createIndexASTConsumer(CI);
146 bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
147 CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks());
151 void EndSourceFileAction() override {
152 FrontendAction::EndSourceFileAction();
157 class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase {
158 bool IndexActionFailed = false;
161 WrappingIndexAction(std::unique_ptr<FrontendAction> WrappedAction,
162 std::shared_ptr<IndexDataConsumer> DataConsumer,
163 IndexingOptions Opts)
164 : WrapperFrontendAction(std::move(WrappedAction)),
165 IndexActionBase(std::move(DataConsumer), Opts) {}
168 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
169 StringRef InFile) override {
170 auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
171 if (!OtherConsumer) {
172 IndexActionFailed = true;
176 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
177 Consumers.push_back(std::move(OtherConsumer));
178 Consumers.push_back(createIndexASTConsumer(CI));
179 return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
182 bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
183 WrapperFrontendAction::BeginSourceFileAction(CI);
184 CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks());
188 void EndSourceFileAction() override {
189 // Invoke wrapped action's method.
190 WrapperFrontendAction::EndSourceFileAction();
191 if (!IndexActionFailed)
196 } // anonymous namespace
198 std::unique_ptr<FrontendAction>
199 index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
200 IndexingOptions Opts,
201 std::unique_ptr<FrontendAction> WrappedAction) {
203 return llvm::make_unique<WrappingIndexAction>(std::move(WrappedAction),
204 std::move(DataConsumer),
206 return llvm::make_unique<IndexAction>(std::move(DataConsumer), Opts);
209 static bool topLevelDeclVisitor(void *context, const Decl *D) {
210 IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context);
211 return IndexCtx.indexTopLevelDecl(D);
214 static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) {
215 Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor);
218 static void indexPreprocessorMacros(const Preprocessor &PP,
219 IndexDataConsumer &DataConsumer) {
220 for (const auto &M : PP.macros())
221 if (MacroDirective *MD = M.second.getLatest())
222 DataConsumer.handleMacroOccurence(
223 M.first, MD->getMacroInfo(),
224 static_cast<unsigned>(index::SymbolRole::Definition),
228 void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,
229 IndexingOptions Opts) {
230 IndexingContext IndexCtx(Opts, DataConsumer);
231 IndexCtx.setASTContext(Unit.getASTContext());
232 DataConsumer.initialize(Unit.getASTContext());
233 DataConsumer.setPreprocessor(Unit.getPreprocessorPtr());
235 if (Opts.IndexMacrosInPreprocessor)
236 indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer);
237 indexTranslationUnit(Unit, IndexCtx);
238 DataConsumer.finish();
241 void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP,
242 ArrayRef<const Decl *> Decls,
243 IndexDataConsumer &DataConsumer,
244 IndexingOptions Opts) {
245 IndexingContext IndexCtx(Opts, DataConsumer);
246 IndexCtx.setASTContext(Ctx);
248 DataConsumer.initialize(Ctx);
250 if (Opts.IndexMacrosInPreprocessor)
251 indexPreprocessorMacros(PP, DataConsumer);
253 for (const Decl *D : Decls)
254 IndexCtx.indexTopLevelDecl(D);
255 DataConsumer.finish();
258 std::unique_ptr<PPCallbacks>
259 index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) {
260 return llvm::make_unique<IndexPPCallbacks>(
261 std::make_shared<IndexingContext>(Opts, Consumer));
264 void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
265 IndexDataConsumer &DataConsumer,
266 IndexingOptions Opts) {
267 ASTContext &Ctx = Reader.getContext();
268 IndexingContext IndexCtx(Opts, DataConsumer);
269 IndexCtx.setASTContext(Ctx);
270 DataConsumer.initialize(Ctx);
272 if (Opts.IndexMacrosInPreprocessor)
273 indexPreprocessorMacros(Reader.getPreprocessor(), DataConsumer);
275 for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) {
276 IndexCtx.indexTopLevelDecl(D);
278 DataConsumer.finish();