311 lines · cpp
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-exception6//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 19using namespace clang;20using namespace clang::index;21 22namespace {23 24class IndexPPCallbacks final : public PPCallbacks {25 std::shared_ptr<IndexingContext> IndexCtx;26 27public: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(*MacroNameTok.getIdentifierInfo(),34 Range.getBegin(), *MD.getMacroInfo());35 }36 37 void MacroDefined(const Token &MacroNameTok,38 const MacroDirective *MD) override {39 IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(),40 MacroNameTok.getLocation(),41 *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(*MacroNameTok.getIdentifierInfo(),49 MacroNameTok.getLocation(),50 *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 M58 IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),59 MacroNameTok.getLocation(),60 *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(*MacroNameTok.getIdentifierInfo(),67 MacroNameTok.getLocation(),68 *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(*MacroNameTok.getIdentifierInfo(),75 MacroNameTok.getLocation(),76 *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(*MacroNameTok.getIdentifierInfo(),86 MacroNameTok.getLocation(),87 *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(*MacroNameTok.getIdentifierInfo(),94 MacroNameTok.getLocation(),95 *MD.getMacroInfo());96 }97};98 99class 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 105public: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 118protected:119 void Initialize(ASTContext &Context) override {120 IndexCtx->setASTContext(Context);121 IndexCtx->getDataConsumer().initialize(Context);122 IndexCtx->getDataConsumer().setPreprocessor(PP);123 PP->addPPCallbacks(std::make_unique<IndexPPCallbacks>(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 147class IndexAction final : public ASTFrontendAction {148 std::shared_ptr<IndexDataConsumer> DataConsumer;149 IndexingOptions Opts;150 151public: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 158protected:159 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,160 StringRef InFile) override {161 return std::make_unique<IndexASTConsumer>(162 DataConsumer, Opts, CI.getPreprocessorPtr(),163 /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; });164 }165};166 167} // anonymous namespace168 169std::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>(DataConsumer, Opts, PP,174 ShouldSkipFunctionBody);175}176 177std::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(std::move(DataConsumer), Opts, std::move(PP),189 std::move(ShouldSkipFunctionBody));190}191 192std::unique_ptr<FrontendAction>193index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,194 const IndexingOptions &Opts) {195 assert(DataConsumer != nullptr);196 return std::make_unique<IndexAction>(std::move(DataConsumer), Opts);197}198 199static bool topLevelDeclVisitor(void *context, const Decl *D) {200 IndexingContext &IndexCtx = *static_cast<IndexingContext *>(context);201 return IndexCtx.indexTopLevelDecl(D);202}203 204static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) {205 Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor);206}207 208static 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 that214 // was defined in another module. In such case, MI may be nullptr, since215 // 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_Define225 ? SymbolRole::Definition226 : SymbolRole::Undefinition;227 DataConsumer.handleMacroOccurrence(II, MI, static_cast<unsigned>(Role), Loc);228}229 230static 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(M.first, MD->getMacroInfo(), MD->getKind(),235 MD->getLocation(), DataConsumer);236 }237 }238}239 240static 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(M.first)) {246 auto *OwningMod = MM->getOwningModule();247 if (OwningMod && OwningMod->getASTFile() == Mod.File) {248 if (auto *MI = MM->getMacroInfo()) {249 indexPreprocessorMacro(M.first, MI, MacroDirective::MD_Define,250 MI->getDefinitionLoc(), DataConsumer);251 }252 }253 }254 }255 }256}257 258void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,259 IndexingOptions Opts) {260 IndexingContext IndexCtx(Opts, DataConsumer);261 IndexCtx.setASTContext(Unit.getASTContext());262 DataConsumer.initialize(Unit.getASTContext());263 DataConsumer.setPreprocessor(Unit.getPreprocessorPtr());264 265 if (Opts.IndexMacrosInPreprocessor)266 indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer);267 indexTranslationUnit(Unit, IndexCtx);268 DataConsumer.finish();269}270 271void 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 288std::unique_ptr<PPCallbacks>289index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) {290 return std::make_unique<IndexPPCallbacks>(291 std::make_shared<IndexingContext>(Opts, Consumer));292}293 294void 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(Reader.getPreprocessor(), Mod, DataConsumer);304 }305 306 for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) {307 IndexCtx.indexTopLevelDecl(D);308 }309 DataConsumer.finish();310}311