10b57cec5SDimitry Andric //===- IndexingAction.cpp - Frontend index action -------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/Index/IndexingAction.h" 100b57cec5SDimitry Andric #include "IndexingContext.h" 110b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h" 120b57cec5SDimitry Andric #include "clang/Frontend/FrontendAction.h" 130b57cec5SDimitry Andric #include "clang/Frontend/MultiplexConsumer.h" 140b57cec5SDimitry Andric #include "clang/Index/IndexDataConsumer.h" 150b57cec5SDimitry Andric #include "clang/Lex/PPCallbacks.h" 160b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 170b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h" 180b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 190b57cec5SDimitry Andric #include <memory> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace clang; 220b57cec5SDimitry Andric using namespace clang::index; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace { 250b57cec5SDimitry Andric 26a7dea167SDimitry Andric class IndexPPCallbacks final : public PPCallbacks { 270b57cec5SDimitry Andric std::shared_ptr<IndexingContext> IndexCtx; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric public: 300b57cec5SDimitry Andric IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx) 310b57cec5SDimitry Andric : IndexCtx(std::move(IndexCtx)) {} 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 340b57cec5SDimitry Andric SourceRange Range, const MacroArgs *Args) override { 350b57cec5SDimitry Andric IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), 360b57cec5SDimitry Andric Range.getBegin(), *MD.getMacroInfo()); 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric void MacroDefined(const Token &MacroNameTok, 400b57cec5SDimitry Andric const MacroDirective *MD) override { 410b57cec5SDimitry Andric IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(), 420b57cec5SDimitry Andric MacroNameTok.getLocation(), 430b57cec5SDimitry Andric *MD->getMacroInfo()); 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, 470b57cec5SDimitry Andric const MacroDirective *Undef) override { 480b57cec5SDimitry Andric if (!MD.getMacroInfo()) // Ignore noop #undef. 490b57cec5SDimitry Andric return; 500b57cec5SDimitry Andric IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(), 510b57cec5SDimitry Andric MacroNameTok.getLocation(), 520b57cec5SDimitry Andric *MD.getMacroInfo()); 530b57cec5SDimitry Andric } 54*fe6060f1SDimitry Andric 55*fe6060f1SDimitry Andric void Defined(const Token &MacroNameTok, const MacroDefinition &MD, 56*fe6060f1SDimitry Andric SourceRange Range) override { 57*fe6060f1SDimitry Andric if (!MD.getMacroInfo()) // Ignore nonexistent macro. 58*fe6060f1SDimitry Andric return; 59*fe6060f1SDimitry Andric // Note: this is defined(M), not #define M 60*fe6060f1SDimitry Andric IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), 61*fe6060f1SDimitry Andric MacroNameTok.getLocation(), 62*fe6060f1SDimitry Andric *MD.getMacroInfo()); 63*fe6060f1SDimitry Andric } 64*fe6060f1SDimitry Andric void Ifdef(SourceLocation Loc, const Token &MacroNameTok, 65*fe6060f1SDimitry Andric const MacroDefinition &MD) override { 66*fe6060f1SDimitry Andric if (!MD.getMacroInfo()) // Ignore non-existent macro. 67*fe6060f1SDimitry Andric return; 68*fe6060f1SDimitry Andric IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), 69*fe6060f1SDimitry Andric MacroNameTok.getLocation(), 70*fe6060f1SDimitry Andric *MD.getMacroInfo()); 71*fe6060f1SDimitry Andric } 72*fe6060f1SDimitry Andric void Ifndef(SourceLocation Loc, const Token &MacroNameTok, 73*fe6060f1SDimitry Andric const MacroDefinition &MD) override { 74*fe6060f1SDimitry Andric if (!MD.getMacroInfo()) // Ignore nonexistent macro. 75*fe6060f1SDimitry Andric return; 76*fe6060f1SDimitry Andric IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), 77*fe6060f1SDimitry Andric MacroNameTok.getLocation(), 78*fe6060f1SDimitry Andric *MD.getMacroInfo()); 79*fe6060f1SDimitry Andric } 80*fe6060f1SDimitry Andric 81*fe6060f1SDimitry Andric using PPCallbacks::Elifdef; 82*fe6060f1SDimitry Andric using PPCallbacks::Elifndef; 83*fe6060f1SDimitry Andric void Elifdef(SourceLocation Loc, const Token &MacroNameTok, 84*fe6060f1SDimitry Andric const MacroDefinition &MD) override { 85*fe6060f1SDimitry Andric if (!MD.getMacroInfo()) // Ignore non-existent macro. 86*fe6060f1SDimitry Andric return; 87*fe6060f1SDimitry Andric IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), 88*fe6060f1SDimitry Andric MacroNameTok.getLocation(), 89*fe6060f1SDimitry Andric *MD.getMacroInfo()); 90*fe6060f1SDimitry Andric } 91*fe6060f1SDimitry Andric void Elifndef(SourceLocation Loc, const Token &MacroNameTok, 92*fe6060f1SDimitry Andric const MacroDefinition &MD) override { 93*fe6060f1SDimitry Andric if (!MD.getMacroInfo()) // Ignore non-existent macro. 94*fe6060f1SDimitry Andric return; 95*fe6060f1SDimitry Andric IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), 96*fe6060f1SDimitry Andric MacroNameTok.getLocation(), 97*fe6060f1SDimitry Andric *MD.getMacroInfo()); 98*fe6060f1SDimitry Andric } 990b57cec5SDimitry Andric }; 1000b57cec5SDimitry Andric 101a7dea167SDimitry Andric class IndexASTConsumer final : public ASTConsumer { 1020b57cec5SDimitry Andric std::shared_ptr<IndexDataConsumer> DataConsumer; 1030b57cec5SDimitry Andric std::shared_ptr<IndexingContext> IndexCtx; 104a7dea167SDimitry Andric std::shared_ptr<Preprocessor> PP; 105a7dea167SDimitry Andric std::function<bool(const Decl *)> ShouldSkipFunctionBody; 1060b57cec5SDimitry Andric 107a7dea167SDimitry Andric public: 108a7dea167SDimitry Andric IndexASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer, 109a7dea167SDimitry Andric const IndexingOptions &Opts, 110a7dea167SDimitry Andric std::shared_ptr<Preprocessor> PP, 111a7dea167SDimitry Andric std::function<bool(const Decl *)> ShouldSkipFunctionBody) 112a7dea167SDimitry Andric : DataConsumer(std::move(DataConsumer)), 113a7dea167SDimitry Andric IndexCtx(new IndexingContext(Opts, *this->DataConsumer)), 114a7dea167SDimitry Andric PP(std::move(PP)), 115a7dea167SDimitry Andric ShouldSkipFunctionBody(std::move(ShouldSkipFunctionBody)) { 116a7dea167SDimitry Andric assert(this->DataConsumer != nullptr); 117a7dea167SDimitry Andric assert(this->PP != nullptr); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 120a7dea167SDimitry Andric protected: 121a7dea167SDimitry Andric void Initialize(ASTContext &Context) override { 122a7dea167SDimitry Andric IndexCtx->setASTContext(Context); 123a7dea167SDimitry Andric IndexCtx->getDataConsumer().initialize(Context); 124a7dea167SDimitry Andric IndexCtx->getDataConsumer().setPreprocessor(PP); 125a7dea167SDimitry Andric PP->addPPCallbacks(std::make_unique<IndexPPCallbacks>(IndexCtx)); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 128a7dea167SDimitry Andric bool HandleTopLevelDecl(DeclGroupRef DG) override { 129a7dea167SDimitry Andric return IndexCtx->indexDeclGroupRef(DG); 130a7dea167SDimitry Andric } 131a7dea167SDimitry Andric 132a7dea167SDimitry Andric void HandleInterestingDecl(DeclGroupRef DG) override { 133a7dea167SDimitry Andric // Ignore deserialized decls. 134a7dea167SDimitry Andric } 135a7dea167SDimitry Andric 136a7dea167SDimitry Andric void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { 137a7dea167SDimitry Andric IndexCtx->indexDeclGroupRef(DG); 138a7dea167SDimitry Andric } 139a7dea167SDimitry Andric 140a7dea167SDimitry Andric void HandleTranslationUnit(ASTContext &Ctx) override { 1410b57cec5SDimitry Andric DataConsumer->finish(); 1420b57cec5SDimitry Andric } 143a7dea167SDimitry Andric 144a7dea167SDimitry Andric bool shouldSkipFunctionBody(Decl *D) override { 145a7dea167SDimitry Andric return ShouldSkipFunctionBody(D); 146a7dea167SDimitry Andric } 1470b57cec5SDimitry Andric }; 1480b57cec5SDimitry Andric 149a7dea167SDimitry Andric class IndexAction final : public ASTFrontendAction { 150a7dea167SDimitry Andric std::shared_ptr<IndexDataConsumer> DataConsumer; 151a7dea167SDimitry Andric IndexingOptions Opts; 152a7dea167SDimitry Andric 1530b57cec5SDimitry Andric public: 1540b57cec5SDimitry Andric IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer, 155a7dea167SDimitry Andric const IndexingOptions &Opts) 156a7dea167SDimitry Andric : DataConsumer(std::move(DataConsumer)), Opts(Opts) { 157a7dea167SDimitry Andric assert(this->DataConsumer != nullptr); 158a7dea167SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric protected: 1610b57cec5SDimitry Andric std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 1620b57cec5SDimitry Andric StringRef InFile) override { 163a7dea167SDimitry Andric return std::make_unique<IndexASTConsumer>( 164a7dea167SDimitry Andric DataConsumer, Opts, CI.getPreprocessorPtr(), 165a7dea167SDimitry Andric /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; }); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric }; 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric } // anonymous namespace 1700b57cec5SDimitry Andric 171a7dea167SDimitry Andric std::unique_ptr<ASTConsumer> index::createIndexingASTConsumer( 172a7dea167SDimitry Andric std::shared_ptr<IndexDataConsumer> DataConsumer, 173a7dea167SDimitry Andric const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP, 174a7dea167SDimitry Andric std::function<bool(const Decl *)> ShouldSkipFunctionBody) { 175a7dea167SDimitry Andric return std::make_unique<IndexASTConsumer>(DataConsumer, Opts, PP, 176a7dea167SDimitry Andric ShouldSkipFunctionBody); 177a7dea167SDimitry Andric } 178a7dea167SDimitry Andric 1795ffd83dbSDimitry Andric std::unique_ptr<ASTConsumer> clang::index::createIndexingASTConsumer( 1805ffd83dbSDimitry Andric std::shared_ptr<IndexDataConsumer> DataConsumer, 1815ffd83dbSDimitry Andric const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP) { 1825ffd83dbSDimitry Andric std::function<bool(const Decl *)> ShouldSkipFunctionBody = [](const Decl *) { 1835ffd83dbSDimitry Andric return false; 1845ffd83dbSDimitry Andric }; 1855ffd83dbSDimitry Andric if (Opts.ShouldTraverseDecl) 1865ffd83dbSDimitry Andric ShouldSkipFunctionBody = 1875ffd83dbSDimitry Andric [ShouldTraverseDecl(Opts.ShouldTraverseDecl)](const Decl *D) { 1885ffd83dbSDimitry Andric return !ShouldTraverseDecl(D); 1895ffd83dbSDimitry Andric }; 1905ffd83dbSDimitry Andric return createIndexingASTConsumer(std::move(DataConsumer), Opts, std::move(PP), 1915ffd83dbSDimitry Andric std::move(ShouldSkipFunctionBody)); 1925ffd83dbSDimitry Andric } 1935ffd83dbSDimitry Andric 1940b57cec5SDimitry Andric std::unique_ptr<FrontendAction> 1950b57cec5SDimitry Andric index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer, 196a7dea167SDimitry Andric const IndexingOptions &Opts) { 197a7dea167SDimitry Andric assert(DataConsumer != nullptr); 198a7dea167SDimitry Andric return std::make_unique<IndexAction>(std::move(DataConsumer), Opts); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric static bool topLevelDeclVisitor(void *context, const Decl *D) { 2020b57cec5SDimitry Andric IndexingContext &IndexCtx = *static_cast<IndexingContext *>(context); 2030b57cec5SDimitry Andric return IndexCtx.indexTopLevelDecl(D); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) { 2070b57cec5SDimitry Andric Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 210*fe6060f1SDimitry Andric static void indexPreprocessorMacro(const IdentifierInfo *II, 211*fe6060f1SDimitry Andric const MacroInfo *MI, 212*fe6060f1SDimitry Andric MacroDirective::Kind DirectiveKind, 213*fe6060f1SDimitry Andric SourceLocation Loc, 2140b57cec5SDimitry Andric IndexDataConsumer &DataConsumer) { 215e8d8bef9SDimitry Andric // When using modules, it may happen that we find #undef of a macro that 216e8d8bef9SDimitry Andric // was defined in another module. In such case, MI may be nullptr, since 217e8d8bef9SDimitry Andric // we only look for macro definitions in the current TU. In that case, 218e8d8bef9SDimitry Andric // there is nothing to index. 219e8d8bef9SDimitry Andric if (!MI) 220*fe6060f1SDimitry Andric return; 221e8d8bef9SDimitry Andric 222*fe6060f1SDimitry Andric // Skip implicit visibility change. 223*fe6060f1SDimitry Andric if (DirectiveKind == MacroDirective::MD_Visibility) 224*fe6060f1SDimitry Andric return; 225*fe6060f1SDimitry Andric 226*fe6060f1SDimitry Andric auto Role = DirectiveKind == MacroDirective::MD_Define 227*fe6060f1SDimitry Andric ? SymbolRole::Definition 228*fe6060f1SDimitry Andric : SymbolRole::Undefinition; 229*fe6060f1SDimitry Andric DataConsumer.handleMacroOccurrence(II, MI, static_cast<unsigned>(Role), Loc); 230*fe6060f1SDimitry Andric } 231*fe6060f1SDimitry Andric 232*fe6060f1SDimitry Andric static void indexPreprocessorMacros(Preprocessor &PP, 233*fe6060f1SDimitry Andric IndexDataConsumer &DataConsumer) { 234*fe6060f1SDimitry Andric for (const auto &M : PP.macros()) { 235*fe6060f1SDimitry Andric for (auto *MD = M.second.getLatest(); MD; MD = MD->getPrevious()) { 236*fe6060f1SDimitry Andric indexPreprocessorMacro(M.first, MD->getMacroInfo(), MD->getKind(), 237*fe6060f1SDimitry Andric MD->getLocation(), DataConsumer); 238*fe6060f1SDimitry Andric } 239*fe6060f1SDimitry Andric } 240*fe6060f1SDimitry Andric } 241*fe6060f1SDimitry Andric 242*fe6060f1SDimitry Andric static void indexPreprocessorModuleMacros(Preprocessor &PP, 243*fe6060f1SDimitry Andric serialization::ModuleFile &Mod, 244*fe6060f1SDimitry Andric IndexDataConsumer &DataConsumer) { 245*fe6060f1SDimitry Andric for (const auto &M : PP.macros()) { 246*fe6060f1SDimitry Andric if (M.second.getLatest() == nullptr) { 247*fe6060f1SDimitry Andric for (auto *MM : PP.getLeafModuleMacros(M.first)) { 248*fe6060f1SDimitry Andric auto *OwningMod = MM->getOwningModule(); 249*fe6060f1SDimitry Andric if (OwningMod && OwningMod->getASTFile() == Mod.File) { 250*fe6060f1SDimitry Andric if (auto *MI = MM->getMacroInfo()) { 251*fe6060f1SDimitry Andric indexPreprocessorMacro(M.first, MI, MacroDirective::MD_Define, 252*fe6060f1SDimitry Andric MI->getDefinitionLoc(), DataConsumer); 253*fe6060f1SDimitry Andric } 254*fe6060f1SDimitry Andric } 255*fe6060f1SDimitry Andric } 256*fe6060f1SDimitry Andric } 2570b57cec5SDimitry Andric } 258e8d8bef9SDimitry Andric } 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, 2610b57cec5SDimitry Andric IndexingOptions Opts) { 2620b57cec5SDimitry Andric IndexingContext IndexCtx(Opts, DataConsumer); 2630b57cec5SDimitry Andric IndexCtx.setASTContext(Unit.getASTContext()); 2640b57cec5SDimitry Andric DataConsumer.initialize(Unit.getASTContext()); 2650b57cec5SDimitry Andric DataConsumer.setPreprocessor(Unit.getPreprocessorPtr()); 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric if (Opts.IndexMacrosInPreprocessor) 2680b57cec5SDimitry Andric indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer); 2690b57cec5SDimitry Andric indexTranslationUnit(Unit, IndexCtx); 2700b57cec5SDimitry Andric DataConsumer.finish(); 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, 2740b57cec5SDimitry Andric ArrayRef<const Decl *> Decls, 2750b57cec5SDimitry Andric IndexDataConsumer &DataConsumer, 2760b57cec5SDimitry Andric IndexingOptions Opts) { 2770b57cec5SDimitry Andric IndexingContext IndexCtx(Opts, DataConsumer); 2780b57cec5SDimitry Andric IndexCtx.setASTContext(Ctx); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric DataConsumer.initialize(Ctx); 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric if (Opts.IndexMacrosInPreprocessor) 2830b57cec5SDimitry Andric indexPreprocessorMacros(PP, DataConsumer); 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric for (const Decl *D : Decls) 2860b57cec5SDimitry Andric IndexCtx.indexTopLevelDecl(D); 2870b57cec5SDimitry Andric DataConsumer.finish(); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric std::unique_ptr<PPCallbacks> 2910b57cec5SDimitry Andric index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) { 292a7dea167SDimitry Andric return std::make_unique<IndexPPCallbacks>( 2930b57cec5SDimitry Andric std::make_shared<IndexingContext>(Opts, Consumer)); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, 2970b57cec5SDimitry Andric IndexDataConsumer &DataConsumer, 2980b57cec5SDimitry Andric IndexingOptions Opts) { 2990b57cec5SDimitry Andric ASTContext &Ctx = Reader.getContext(); 3000b57cec5SDimitry Andric IndexingContext IndexCtx(Opts, DataConsumer); 3010b57cec5SDimitry Andric IndexCtx.setASTContext(Ctx); 3020b57cec5SDimitry Andric DataConsumer.initialize(Ctx); 3030b57cec5SDimitry Andric 304*fe6060f1SDimitry Andric if (Opts.IndexMacrosInPreprocessor) { 305*fe6060f1SDimitry Andric indexPreprocessorModuleMacros(Reader.getPreprocessor(), Mod, DataConsumer); 306*fe6060f1SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { 3090b57cec5SDimitry Andric IndexCtx.indexTopLevelDecl(D); 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric DataConsumer.finish(); 3120b57cec5SDimitry Andric } 313