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