1 //===- IndexingAction.cpp - Frontend index action -------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/Index/IndexingAction.h"
11 #include "IndexingContext.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Frontend/FrontendAction.h"
14 #include "clang/Frontend/MultiplexConsumer.h"
15 #include "clang/Index/IndexDataConsumer.h"
16 #include "clang/Lex/PPCallbacks.h"
17 #include "clang/Lex/Preprocessor.h"
18 #include "clang/Serialization/ASTReader.h"
19 #include "llvm/ADT/STLExtras.h"
22 using namespace clang;
23 using namespace clang::index;
25 bool IndexDataConsumer::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
26 ArrayRef<SymbolRelation> Relations,
28 ASTNodeInfo ASTNode) {
32 bool IndexDataConsumer::handleMacroOccurence(const IdentifierInfo *Name,
39 bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD,
48 class IndexASTConsumer : public ASTConsumer {
49 std::shared_ptr<Preprocessor> PP;
50 std::shared_ptr<IndexingContext> IndexCtx;
53 IndexASTConsumer(std::shared_ptr<Preprocessor> PP,
54 std::shared_ptr<IndexingContext> IndexCtx)
55 : PP(std::move(PP)), IndexCtx(std::move(IndexCtx)) {}
58 void Initialize(ASTContext &Context) override {
59 IndexCtx->setASTContext(Context);
60 IndexCtx->getDataConsumer().initialize(Context);
61 IndexCtx->getDataConsumer().setPreprocessor(PP);
64 bool HandleTopLevelDecl(DeclGroupRef DG) override {
65 return IndexCtx->indexDeclGroupRef(DG);
68 void HandleInterestingDecl(DeclGroupRef DG) override {
69 // Ignore deserialized decls.
72 void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
73 IndexCtx->indexDeclGroupRef(DG);
76 void HandleTranslationUnit(ASTContext &Ctx) override {
80 class IndexPPCallbacks : public PPCallbacks {
81 std::shared_ptr<IndexingContext> IndexCtx;
84 IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx)
85 : IndexCtx(std::move(IndexCtx)) {}
87 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
88 SourceRange Range, const MacroArgs *Args) override {
89 IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
90 Range.getBegin(), *MD.getMacroInfo());
93 void MacroDefined(const Token &MacroNameTok,
94 const MacroDirective *MD) override {
95 IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(),
96 MacroNameTok.getLocation(),
100 void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
101 const MacroDirective *Undef) override {
102 if (!MD.getMacroInfo()) // Ignore noop #undef.
104 IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(),
105 MacroNameTok.getLocation(),
110 class IndexActionBase {
112 std::shared_ptr<IndexDataConsumer> DataConsumer;
113 std::shared_ptr<IndexingContext> IndexCtx;
115 IndexActionBase(std::shared_ptr<IndexDataConsumer> dataConsumer,
116 IndexingOptions Opts)
117 : DataConsumer(std::move(dataConsumer)),
118 IndexCtx(new IndexingContext(Opts, *DataConsumer)) {}
120 std::unique_ptr<IndexASTConsumer>
121 createIndexASTConsumer(CompilerInstance &CI) {
122 return llvm::make_unique<IndexASTConsumer>(CI.getPreprocessorPtr(),
126 std::unique_ptr<PPCallbacks> createIndexPPCallbacks() {
127 return llvm::make_unique<IndexPPCallbacks>(IndexCtx);
131 DataConsumer->finish();
135 class IndexAction : public ASTFrontendAction, IndexActionBase {
137 IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
138 IndexingOptions Opts)
139 : IndexActionBase(std::move(DataConsumer), Opts) {}
142 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
143 StringRef InFile) override {
144 return createIndexASTConsumer(CI);
147 bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
148 CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks());
152 void EndSourceFileAction() override {
153 FrontendAction::EndSourceFileAction();
158 class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase {
159 bool IndexActionFailed = false;
162 WrappingIndexAction(std::unique_ptr<FrontendAction> WrappedAction,
163 std::shared_ptr<IndexDataConsumer> DataConsumer,
164 IndexingOptions Opts)
165 : WrapperFrontendAction(std::move(WrappedAction)),
166 IndexActionBase(std::move(DataConsumer), Opts) {}
169 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
170 StringRef InFile) override {
171 auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
172 if (!OtherConsumer) {
173 IndexActionFailed = true;
177 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
178 Consumers.push_back(std::move(OtherConsumer));
179 Consumers.push_back(createIndexASTConsumer(CI));
180 return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
183 bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
184 WrapperFrontendAction::BeginSourceFileAction(CI);
185 CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks());
189 void EndSourceFileAction() override {
190 // Invoke wrapped action's method.
191 WrapperFrontendAction::EndSourceFileAction();
192 if (!IndexActionFailed)
197 } // anonymous namespace
199 std::unique_ptr<FrontendAction>
200 index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
201 IndexingOptions Opts,
202 std::unique_ptr<FrontendAction> WrappedAction) {
204 return llvm::make_unique<WrappingIndexAction>(std::move(WrappedAction),
205 std::move(DataConsumer),
207 return llvm::make_unique<IndexAction>(std::move(DataConsumer), Opts);
210 static bool topLevelDeclVisitor(void *context, const Decl *D) {
211 IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context);
212 return IndexCtx.indexTopLevelDecl(D);
215 static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) {
216 Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor);
219 static void indexPreprocessorMacros(const Preprocessor &PP,
220 IndexDataConsumer &DataConsumer) {
221 for (const auto &M : PP.macros())
222 if (MacroDirective *MD = M.second.getLatest())
223 DataConsumer.handleMacroOccurence(
224 M.first, MD->getMacroInfo(),
225 static_cast<unsigned>(index::SymbolRole::Definition),
229 void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,
230 IndexingOptions Opts) {
231 IndexingContext IndexCtx(Opts, DataConsumer);
232 IndexCtx.setASTContext(Unit.getASTContext());
233 DataConsumer.initialize(Unit.getASTContext());
234 DataConsumer.setPreprocessor(Unit.getPreprocessorPtr());
236 if (Opts.IndexMacrosInPreprocessor)
237 indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer);
238 indexTranslationUnit(Unit, IndexCtx);
239 DataConsumer.finish();
242 void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP,
243 ArrayRef<const Decl *> Decls,
244 IndexDataConsumer &DataConsumer,
245 IndexingOptions Opts) {
246 IndexingContext IndexCtx(Opts, DataConsumer);
247 IndexCtx.setASTContext(Ctx);
249 DataConsumer.initialize(Ctx);
251 if (Opts.IndexMacrosInPreprocessor)
252 indexPreprocessorMacros(PP, DataConsumer);
254 for (const Decl *D : Decls)
255 IndexCtx.indexTopLevelDecl(D);
256 DataConsumer.finish();
259 std::unique_ptr<PPCallbacks>
260 index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) {
261 return llvm::make_unique<IndexPPCallbacks>(
262 std::make_shared<IndexingContext>(Opts, Consumer));
265 void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
266 IndexDataConsumer &DataConsumer,
267 IndexingOptions Opts) {
268 ASTContext &Ctx = Reader.getContext();
269 IndexingContext IndexCtx(Opts, DataConsumer);
270 IndexCtx.setASTContext(Ctx);
271 DataConsumer.initialize(Ctx);
273 if (Opts.IndexMacrosInPreprocessor)
274 indexPreprocessorMacros(Reader.getPreprocessor(), DataConsumer);
276 for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) {
277 IndexCtx.indexTopLevelDecl(D);
279 DataConsumer.finish();