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