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/Preprocessor.h"
17 #include "clang/Serialization/ASTReader.h"
18 
19 using namespace clang;
20 using namespace clang::index;
21 
22 void IndexDataConsumer::_anchor() {}
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                                               SymbolRoleSet Roles,
40                                               SourceLocation Loc) {
41   return true;
42 }
43 
44 namespace {
45 
46 class IndexASTConsumer : public ASTConsumer {
47   std::shared_ptr<Preprocessor> PP;
48   IndexingContext &IndexCtx;
49 
50 public:
51   IndexASTConsumer(std::shared_ptr<Preprocessor> PP, IndexingContext &IndexCtx)
52       : PP(std::move(PP)), IndexCtx(IndexCtx) {}
53 
54 protected:
55   void Initialize(ASTContext &Context) override {
56     IndexCtx.setASTContext(Context);
57     IndexCtx.getDataConsumer().initialize(Context);
58     IndexCtx.getDataConsumer().setPreprocessor(PP);
59   }
60 
61   bool HandleTopLevelDecl(DeclGroupRef DG) override {
62     return IndexCtx.indexDeclGroupRef(DG);
63   }
64 
65   void HandleInterestingDecl(DeclGroupRef DG) override {
66     // Ignore deserialized decls.
67   }
68 
69   void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
70     IndexCtx.indexDeclGroupRef(DG);
71   }
72 
73   void HandleTranslationUnit(ASTContext &Ctx) override {
74   }
75 };
76 
77 class IndexActionBase {
78 protected:
79   std::shared_ptr<IndexDataConsumer> DataConsumer;
80   IndexingContext IndexCtx;
81 
82   IndexActionBase(std::shared_ptr<IndexDataConsumer> dataConsumer,
83                   IndexingOptions Opts)
84     : DataConsumer(std::move(dataConsumer)),
85       IndexCtx(Opts, *DataConsumer) {}
86 
87   std::unique_ptr<IndexASTConsumer>
88   createIndexASTConsumer(CompilerInstance &CI) {
89     return llvm::make_unique<IndexASTConsumer>(CI.getPreprocessorPtr(),
90                                                IndexCtx);
91   }
92 
93   void finish() {
94     DataConsumer->finish();
95   }
96 };
97 
98 class IndexAction : public ASTFrontendAction, IndexActionBase {
99 public:
100   IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
101               IndexingOptions Opts)
102     : IndexActionBase(std::move(DataConsumer), Opts) {}
103 
104 protected:
105   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
106                                                  StringRef InFile) override {
107     return createIndexASTConsumer(CI);
108   }
109 
110   void EndSourceFileAction() override {
111     FrontendAction::EndSourceFileAction();
112     finish();
113   }
114 };
115 
116 class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase {
117   bool IndexActionFailed = false;
118 
119 public:
120   WrappingIndexAction(std::unique_ptr<FrontendAction> WrappedAction,
121                       std::shared_ptr<IndexDataConsumer> DataConsumer,
122                       IndexingOptions Opts)
123     : WrapperFrontendAction(std::move(WrappedAction)),
124       IndexActionBase(std::move(DataConsumer), Opts) {}
125 
126 protected:
127   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
128                                                  StringRef InFile) override;
129   void EndSourceFileAction() override;
130 };
131 
132 } // anonymous namespace
133 
134 void WrappingIndexAction::EndSourceFileAction() {
135   // Invoke wrapped action's method.
136   WrapperFrontendAction::EndSourceFileAction();
137   if (!IndexActionFailed)
138     finish();
139 }
140 
141 std::unique_ptr<ASTConsumer>
142 WrappingIndexAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
143   auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
144   if (!OtherConsumer) {
145     IndexActionFailed = true;
146     return nullptr;
147   }
148 
149   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
150   Consumers.push_back(std::move(OtherConsumer));
151   Consumers.push_back(createIndexASTConsumer(CI));
152   return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
153 }
154 
155 std::unique_ptr<FrontendAction>
156 index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
157                             IndexingOptions Opts,
158                             std::unique_ptr<FrontendAction> WrappedAction) {
159   if (WrappedAction)
160     return llvm::make_unique<WrappingIndexAction>(std::move(WrappedAction),
161                                                   std::move(DataConsumer),
162                                                   Opts);
163   return llvm::make_unique<IndexAction>(std::move(DataConsumer), Opts);
164 }
165 
166 
167 static bool topLevelDeclVisitor(void *context, const Decl *D) {
168   IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context);
169   return IndexCtx.indexTopLevelDecl(D);
170 }
171 
172 static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) {
173   Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor);
174 }
175 
176 void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,
177                          IndexingOptions Opts) {
178   IndexingContext IndexCtx(Opts, DataConsumer);
179   IndexCtx.setASTContext(Unit.getASTContext());
180   DataConsumer.initialize(Unit.getASTContext());
181   DataConsumer.setPreprocessor(Unit.getPreprocessorPtr());
182   indexTranslationUnit(Unit, IndexCtx);
183   DataConsumer.finish();
184 }
185 
186 void index::indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls,
187                                IndexDataConsumer &DataConsumer,
188                                IndexingOptions Opts) {
189   IndexingContext IndexCtx(Opts, DataConsumer);
190   IndexCtx.setASTContext(Ctx);
191 
192   DataConsumer.initialize(Ctx);
193   for (const Decl *D : Decls)
194     IndexCtx.indexTopLevelDecl(D);
195   DataConsumer.finish();
196 }
197 
198 void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
199                             IndexDataConsumer &DataConsumer,
200                             IndexingOptions Opts) {
201   ASTContext &Ctx = Reader.getContext();
202   IndexingContext IndexCtx(Opts, DataConsumer);
203   IndexCtx.setASTContext(Ctx);
204   DataConsumer.initialize(Ctx);
205 
206   for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) {
207     IndexCtx.indexTopLevelDecl(D);
208   }
209   DataConsumer.finish();
210 }
211