xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Index/IndexingAction.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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 namespace {
25 
26 class IndexPPCallbacks final : public PPCallbacks {
27   std::shared_ptr<IndexingContext> IndexCtx;
28 
29 public:
IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx)30   IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx)
31       : IndexCtx(std::move(IndexCtx)) {}
32 
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)33   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
34                     SourceRange Range, const MacroArgs *Args) override {
35     IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
36                                    Range.getBegin(), *MD.getMacroInfo());
37   }
38 
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)39   void MacroDefined(const Token &MacroNameTok,
40                     const MacroDirective *MD) override {
41     IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(),
42                                  MacroNameTok.getLocation(),
43                                  *MD->getMacroInfo());
44   }
45 
MacroUndefined(const Token & MacroNameTok,const MacroDefinition & MD,const MacroDirective * Undef)46   void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
47                       const MacroDirective *Undef) override {
48     if (!MD.getMacroInfo())  // Ignore noop #undef.
49       return;
50     IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(),
51                                    MacroNameTok.getLocation(),
52                                    *MD.getMacroInfo());
53   }
54 
Defined(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range)55   void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
56                SourceRange Range) override {
57     if (!MD.getMacroInfo()) // Ignore nonexistent macro.
58       return;
59     // Note: this is defined(M), not #define M
60     IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
61                                    MacroNameTok.getLocation(),
62                                    *MD.getMacroInfo());
63   }
Ifdef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)64   void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
65              const MacroDefinition &MD) override {
66     if (!MD.getMacroInfo()) // Ignore non-existent macro.
67       return;
68     IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
69                                    MacroNameTok.getLocation(),
70                                    *MD.getMacroInfo());
71   }
Ifndef(SourceLocation Loc,const Token & MacroNameTok,const MacroDefinition & MD)72   void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
73               const MacroDefinition &MD) override {
74     if (!MD.getMacroInfo()) // Ignore nonexistent macro.
75       return;
76     IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
77                                    MacroNameTok.getLocation(),
78                                    *MD.getMacroInfo());
79   }
80 };
81 
82 class IndexASTConsumer final : public ASTConsumer {
83   std::shared_ptr<IndexDataConsumer> DataConsumer;
84   std::shared_ptr<IndexingContext> IndexCtx;
85   std::shared_ptr<Preprocessor> PP;
86   std::function<bool(const Decl *)> ShouldSkipFunctionBody;
87 
88 public:
IndexASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer,const IndexingOptions & Opts,std::shared_ptr<Preprocessor> PP,std::function<bool (const Decl *)> ShouldSkipFunctionBody)89   IndexASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer,
90                    const IndexingOptions &Opts,
91                    std::shared_ptr<Preprocessor> PP,
92                    std::function<bool(const Decl *)> ShouldSkipFunctionBody)
93       : DataConsumer(std::move(DataConsumer)),
94         IndexCtx(new IndexingContext(Opts, *this->DataConsumer)),
95         PP(std::move(PP)),
96         ShouldSkipFunctionBody(std::move(ShouldSkipFunctionBody)) {
97     assert(this->DataConsumer != nullptr);
98     assert(this->PP != nullptr);
99   }
100 
101 protected:
Initialize(ASTContext & Context)102   void Initialize(ASTContext &Context) override {
103     IndexCtx->setASTContext(Context);
104     IndexCtx->getDataConsumer().initialize(Context);
105     IndexCtx->getDataConsumer().setPreprocessor(PP);
106     PP->addPPCallbacks(std::make_unique<IndexPPCallbacks>(IndexCtx));
107   }
108 
HandleTopLevelDecl(DeclGroupRef DG)109   bool HandleTopLevelDecl(DeclGroupRef DG) override {
110     return IndexCtx->indexDeclGroupRef(DG);
111   }
112 
HandleInterestingDecl(DeclGroupRef DG)113   void HandleInterestingDecl(DeclGroupRef DG) override {
114     // Ignore deserialized decls.
115   }
116 
HandleTopLevelDeclInObjCContainer(DeclGroupRef DG)117   void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
118     IndexCtx->indexDeclGroupRef(DG);
119   }
120 
HandleTranslationUnit(ASTContext & Ctx)121   void HandleTranslationUnit(ASTContext &Ctx) override {
122     DataConsumer->finish();
123   }
124 
shouldSkipFunctionBody(Decl * D)125   bool shouldSkipFunctionBody(Decl *D) override {
126     return ShouldSkipFunctionBody(D);
127   }
128 };
129 
130 class IndexAction final : public ASTFrontendAction {
131   std::shared_ptr<IndexDataConsumer> DataConsumer;
132   IndexingOptions Opts;
133 
134 public:
IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,const IndexingOptions & Opts)135   IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
136               const IndexingOptions &Opts)
137       : DataConsumer(std::move(DataConsumer)), Opts(Opts) {
138     assert(this->DataConsumer != nullptr);
139   }
140 
141 protected:
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)142   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
143                                                  StringRef InFile) override {
144     return std::make_unique<IndexASTConsumer>(
145         DataConsumer, Opts, CI.getPreprocessorPtr(),
146         /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; });
147   }
148 };
149 
150 } // anonymous namespace
151 
createIndexingASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer,const IndexingOptions & Opts,std::shared_ptr<Preprocessor> PP,std::function<bool (const Decl *)> ShouldSkipFunctionBody)152 std::unique_ptr<ASTConsumer> index::createIndexingASTConsumer(
153     std::shared_ptr<IndexDataConsumer> DataConsumer,
154     const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP,
155     std::function<bool(const Decl *)> ShouldSkipFunctionBody) {
156   return std::make_unique<IndexASTConsumer>(DataConsumer, Opts, PP,
157                                             ShouldSkipFunctionBody);
158 }
159 
createIndexingASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer,const IndexingOptions & Opts,std::shared_ptr<Preprocessor> PP)160 std::unique_ptr<ASTConsumer> clang::index::createIndexingASTConsumer(
161     std::shared_ptr<IndexDataConsumer> DataConsumer,
162     const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP) {
163   std::function<bool(const Decl *)> ShouldSkipFunctionBody = [](const Decl *) {
164     return false;
165   };
166   if (Opts.ShouldTraverseDecl)
167     ShouldSkipFunctionBody =
168         [ShouldTraverseDecl(Opts.ShouldTraverseDecl)](const Decl *D) {
169           return !ShouldTraverseDecl(D);
170         };
171   return createIndexingASTConsumer(std::move(DataConsumer), Opts, std::move(PP),
172                                    std::move(ShouldSkipFunctionBody));
173 }
174 
175 std::unique_ptr<FrontendAction>
createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,const IndexingOptions & Opts)176 index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
177                             const IndexingOptions &Opts) {
178   assert(DataConsumer != nullptr);
179   return std::make_unique<IndexAction>(std::move(DataConsumer), Opts);
180 }
181 
topLevelDeclVisitor(void * context,const Decl * D)182 static bool topLevelDeclVisitor(void *context, const Decl *D) {
183   IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context);
184   return IndexCtx.indexTopLevelDecl(D);
185 }
186 
indexTranslationUnit(ASTUnit & Unit,IndexingContext & IndexCtx)187 static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) {
188   Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor);
189 }
190 
indexPreprocessorMacro(const IdentifierInfo * II,const MacroInfo * MI,MacroDirective::Kind DirectiveKind,SourceLocation Loc,IndexDataConsumer & DataConsumer)191 static void indexPreprocessorMacro(const IdentifierInfo *II,
192                                    const MacroInfo *MI,
193                                    MacroDirective::Kind DirectiveKind,
194                                    SourceLocation Loc,
195                                    IndexDataConsumer &DataConsumer) {
196   // When using modules, it may happen that we find #undef of a macro that
197   // was defined in another module. In such case, MI may be nullptr, since
198   // we only look for macro definitions in the current TU. In that case,
199   // there is nothing to index.
200   if (!MI)
201     return;
202 
203   // Skip implicit visibility change.
204   if (DirectiveKind == MacroDirective::MD_Visibility)
205     return;
206 
207   auto Role = DirectiveKind == MacroDirective::MD_Define
208                   ? SymbolRole::Definition
209                   : SymbolRole::Undefinition;
210   DataConsumer.handleMacroOccurrence(II, MI, static_cast<unsigned>(Role), Loc);
211 }
212 
indexPreprocessorMacros(Preprocessor & PP,IndexDataConsumer & DataConsumer)213 static void indexPreprocessorMacros(Preprocessor &PP,
214                                     IndexDataConsumer &DataConsumer) {
215   for (const auto &M : PP.macros()) {
216     for (auto *MD = M.second.getLatest(); MD; MD = MD->getPrevious()) {
217       indexPreprocessorMacro(M.first, MD->getMacroInfo(), MD->getKind(),
218                              MD->getLocation(), DataConsumer);
219     }
220   }
221 }
222 
indexPreprocessorModuleMacros(Preprocessor & PP,serialization::ModuleFile & Mod,IndexDataConsumer & DataConsumer)223 static void indexPreprocessorModuleMacros(Preprocessor &PP,
224                                           serialization::ModuleFile &Mod,
225                                           IndexDataConsumer &DataConsumer) {
226   for (const auto &M : PP.macros()) {
227     if (M.second.getLatest() == nullptr) {
228       for (auto *MM : PP.getLeafModuleMacros(M.first)) {
229         auto *OwningMod = MM->getOwningModule();
230         if (OwningMod && OwningMod->getASTFile() == Mod.File) {
231           if (auto *MI = MM->getMacroInfo()) {
232             indexPreprocessorMacro(M.first, MI, MacroDirective::MD_Define,
233                                    MI->getDefinitionLoc(), DataConsumer);
234           }
235         }
236       }
237     }
238   }
239 }
240 
indexASTUnit(ASTUnit & Unit,IndexDataConsumer & DataConsumer,IndexingOptions Opts)241 void index::indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,
242                          IndexingOptions Opts) {
243   IndexingContext IndexCtx(Opts, DataConsumer);
244   IndexCtx.setASTContext(Unit.getASTContext());
245   DataConsumer.initialize(Unit.getASTContext());
246   DataConsumer.setPreprocessor(Unit.getPreprocessorPtr());
247 
248   if (Opts.IndexMacrosInPreprocessor)
249     indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer);
250   indexTranslationUnit(Unit, IndexCtx);
251   DataConsumer.finish();
252 }
253 
indexTopLevelDecls(ASTContext & Ctx,Preprocessor & PP,ArrayRef<const Decl * > Decls,IndexDataConsumer & DataConsumer,IndexingOptions Opts)254 void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP,
255                                ArrayRef<const Decl *> Decls,
256                                IndexDataConsumer &DataConsumer,
257                                IndexingOptions Opts) {
258   IndexingContext IndexCtx(Opts, DataConsumer);
259   IndexCtx.setASTContext(Ctx);
260 
261   DataConsumer.initialize(Ctx);
262 
263   if (Opts.IndexMacrosInPreprocessor)
264     indexPreprocessorMacros(PP, DataConsumer);
265 
266   for (const Decl *D : Decls)
267     IndexCtx.indexTopLevelDecl(D);
268   DataConsumer.finish();
269 }
270 
271 std::unique_ptr<PPCallbacks>
indexMacrosCallback(IndexDataConsumer & Consumer,IndexingOptions Opts)272 index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) {
273   return std::make_unique<IndexPPCallbacks>(
274       std::make_shared<IndexingContext>(Opts, Consumer));
275 }
276 
indexModuleFile(serialization::ModuleFile & Mod,ASTReader & Reader,IndexDataConsumer & DataConsumer,IndexingOptions Opts)277 void index::indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
278                             IndexDataConsumer &DataConsumer,
279                             IndexingOptions Opts) {
280   ASTContext &Ctx = Reader.getContext();
281   IndexingContext IndexCtx(Opts, DataConsumer);
282   IndexCtx.setASTContext(Ctx);
283   DataConsumer.initialize(Ctx);
284 
285   if (Opts.IndexMacrosInPreprocessor) {
286     indexPreprocessorModuleMacros(Reader.getPreprocessor(), Mod, DataConsumer);
287   }
288 
289   for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) {
290     IndexCtx.indexTopLevelDecl(D);
291   }
292   DataConsumer.finish();
293 }
294