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