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                                               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 void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,
219                          IndexingOptions Opts) {
220   IndexingContext IndexCtx(Opts, DataConsumer);
221   IndexCtx.setASTContext(Unit.getASTContext());
222   DataConsumer.initialize(Unit.getASTContext());
223   DataConsumer.setPreprocessor(Unit.getPreprocessorPtr());
224   indexTranslationUnit(Unit, IndexCtx);
225   DataConsumer.finish();
226 }
227 
228 void index::indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls,
229                                IndexDataConsumer &DataConsumer,
230                                IndexingOptions Opts) {
231   IndexingContext IndexCtx(Opts, DataConsumer);
232   IndexCtx.setASTContext(Ctx);
233 
234   DataConsumer.initialize(Ctx);
235   for (const Decl *D : Decls)
236     IndexCtx.indexTopLevelDecl(D);
237   DataConsumer.finish();
238 }
239 
240 std::unique_ptr<PPCallbacks>
241 index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) {
242   return llvm::make_unique<IndexPPCallbacks>(
243       std::make_shared<IndexingContext>(Opts, Consumer));
244 }
245 
246 void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
247                             IndexDataConsumer &DataConsumer,
248                             IndexingOptions Opts) {
249   ASTContext &Ctx = Reader.getContext();
250   IndexingContext IndexCtx(Opts, DataConsumer);
251   IndexCtx.setASTContext(Ctx);
252   DataConsumer.initialize(Ctx);
253 
254   for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) {
255     IndexCtx.indexTopLevelDecl(D);
256   }
257   DataConsumer.finish();
258 }
259