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(*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 M 58 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 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(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 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 DataConsumer, Opts, CI.getPreprocessorPtr(), 163 /*ShouldSkipFunctionBody=*/[](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>(DataConsumer, Opts, PP, 174 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(std::move(DataConsumer), Opts, std::move(PP), 189 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>(std::move(DataConsumer), 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(&IndexCtx, 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(II, MI, 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(M.first, MD->getMacroInfo(), MD->getKind(), 235 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(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 258 void 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 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 std::make_shared<IndexingContext>(Opts, 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(Reader.getPreprocessor(), Mod, DataConsumer); 304 } 305 306 for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { 307 IndexCtx.indexTopLevelDecl(D); 308 } 309 DataConsumer.finish(); 310 } 311