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