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/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" 19 #include <memory> 20 21 using namespace clang; 22 using namespace clang::index; 23 24 bool IndexDataConsumer::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, 25 ArrayRef<SymbolRelation> Relations, 26 SourceLocation Loc, 27 ASTNodeInfo ASTNode) { 28 return true; 29 } 30 31 bool IndexDataConsumer::handleMacroOccurence(const IdentifierInfo *Name, 32 const MacroInfo *MI, 33 SymbolRoleSet Roles, 34 SourceLocation Loc) { 35 return true; 36 } 37 38 bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD, 39 const Module *Mod, 40 SymbolRoleSet Roles, 41 SourceLocation Loc) { 42 return true; 43 } 44 45 namespace { 46 47 class IndexASTConsumer : public ASTConsumer { 48 std::shared_ptr<Preprocessor> PP; 49 std::shared_ptr<IndexingContext> IndexCtx; 50 51 public: 52 IndexASTConsumer(std::shared_ptr<Preprocessor> PP, 53 std::shared_ptr<IndexingContext> IndexCtx) 54 : PP(std::move(PP)), IndexCtx(std::move(IndexCtx)) {} 55 56 protected: 57 void Initialize(ASTContext &Context) override { 58 IndexCtx->setASTContext(Context); 59 IndexCtx->getDataConsumer().initialize(Context); 60 IndexCtx->getDataConsumer().setPreprocessor(PP); 61 } 62 63 bool HandleTopLevelDecl(DeclGroupRef DG) override { 64 return IndexCtx->indexDeclGroupRef(DG); 65 } 66 67 void HandleInterestingDecl(DeclGroupRef DG) override { 68 // Ignore deserialized decls. 69 } 70 71 void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { 72 IndexCtx->indexDeclGroupRef(DG); 73 } 74 75 void HandleTranslationUnit(ASTContext &Ctx) override { 76 } 77 }; 78 79 class IndexPPCallbacks : public PPCallbacks { 80 std::shared_ptr<IndexingContext> IndexCtx; 81 82 public: 83 IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx) 84 : IndexCtx(std::move(IndexCtx)) {} 85 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()); 90 } 91 92 void MacroDefined(const Token &MacroNameTok, 93 const MacroDirective *MD) override { 94 IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(), 95 MacroNameTok.getLocation(), 96 *MD->getMacroInfo()); 97 } 98 99 void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, 100 const MacroDirective *Undef) override { 101 if (!MD.getMacroInfo()) // Ignore noop #undef. 102 return; 103 IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(), 104 MacroNameTok.getLocation(), 105 *MD.getMacroInfo()); 106 } 107 }; 108 109 class IndexActionBase { 110 protected: 111 std::shared_ptr<IndexDataConsumer> DataConsumer; 112 std::shared_ptr<IndexingContext> IndexCtx; 113 114 IndexActionBase(std::shared_ptr<IndexDataConsumer> dataConsumer, 115 IndexingOptions Opts) 116 : DataConsumer(std::move(dataConsumer)), 117 IndexCtx(new IndexingContext(Opts, *DataConsumer)) {} 118 119 std::unique_ptr<IndexASTConsumer> 120 createIndexASTConsumer(CompilerInstance &CI) { 121 return llvm::make_unique<IndexASTConsumer>(CI.getPreprocessorPtr(), 122 IndexCtx); 123 } 124 125 std::unique_ptr<PPCallbacks> createIndexPPCallbacks() { 126 return llvm::make_unique<IndexPPCallbacks>(IndexCtx); 127 } 128 129 void finish() { 130 DataConsumer->finish(); 131 } 132 }; 133 134 class IndexAction : public ASTFrontendAction, IndexActionBase { 135 public: 136 IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer, 137 IndexingOptions Opts) 138 : IndexActionBase(std::move(DataConsumer), Opts) {} 139 140 protected: 141 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 142 StringRef InFile) override { 143 return createIndexASTConsumer(CI); 144 } 145 146 bool BeginSourceFileAction(clang::CompilerInstance &CI) override { 147 CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks()); 148 return true; 149 } 150 151 void EndSourceFileAction() override { 152 FrontendAction::EndSourceFileAction(); 153 finish(); 154 } 155 }; 156 157 class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase { 158 bool IndexActionFailed = false; 159 160 public: 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) {} 166 167 protected: 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; 173 return nullptr; 174 } 175 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)); 180 } 181 182 bool BeginSourceFileAction(clang::CompilerInstance &CI) override { 183 WrapperFrontendAction::BeginSourceFileAction(CI); 184 CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks()); 185 return true; 186 } 187 188 void EndSourceFileAction() override { 189 // Invoke wrapped action's method. 190 WrapperFrontendAction::EndSourceFileAction(); 191 if (!IndexActionFailed) 192 finish(); 193 } 194 }; 195 196 } // anonymous namespace 197 198 std::unique_ptr<FrontendAction> 199 index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer, 200 IndexingOptions Opts, 201 std::unique_ptr<FrontendAction> WrappedAction) { 202 if (WrappedAction) 203 return llvm::make_unique<WrappingIndexAction>(std::move(WrappedAction), 204 std::move(DataConsumer), 205 Opts); 206 return llvm::make_unique<IndexAction>(std::move(DataConsumer), Opts); 207 } 208 209 static bool topLevelDeclVisitor(void *context, const Decl *D) { 210 IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context); 211 return IndexCtx.indexTopLevelDecl(D); 212 } 213 214 static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) { 215 Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor); 216 } 217 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), 225 MD->getLocation()); 226 } 227 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()); 234 235 if (Opts.IndexMacrosInPreprocessor) 236 indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer); 237 indexTranslationUnit(Unit, IndexCtx); 238 DataConsumer.finish(); 239 } 240 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); 247 248 DataConsumer.initialize(Ctx); 249 250 if (Opts.IndexMacrosInPreprocessor) 251 indexPreprocessorMacros(PP, DataConsumer); 252 253 for (const Decl *D : Decls) 254 IndexCtx.indexTopLevelDecl(D); 255 DataConsumer.finish(); 256 } 257 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)); 262 } 263 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); 271 272 if (Opts.IndexMacrosInPreprocessor) 273 indexPreprocessorMacros(Reader.getPreprocessor(), DataConsumer); 274 275 for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { 276 IndexCtx.indexTopLevelDecl(D); 277 } 278 DataConsumer.finish(); 279 } 280