clang  19.0.0git
IndexingAction.cpp
Go to the documentation of this file.
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 
10 #include "IndexingContext.h"
15 #include "clang/Lex/PPCallbacks.h"
16 #include "clang/Lex/Preprocessor.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:
30  IndexPPCallbacks(std::shared_ptr<IndexingContext> IndexCtx)
31  : IndexCtx(std::move(IndexCtx)) {}
32 
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 
39  void MacroDefined(const Token &MacroNameTok,
40  const MacroDirective *MD) override {
41  IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(),
42  MacroNameTok.getLocation(),
43  *MD->getMacroInfo());
44  }
45 
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 
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  }
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  }
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 
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  }
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:
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:
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 
128  bool HandleTopLevelDecl(DeclGroupRef DG) override {
129  return IndexCtx->indexDeclGroupRef(DG);
130  }
131 
132  void HandleInterestingDecl(DeclGroupRef DG) override {
133  // Ignore deserialized decls.
134  }
135 
136  void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
137  IndexCtx->indexDeclGroupRef(DG);
138  }
139 
140  void HandleTranslationUnit(ASTContext &Ctx) override {
141  DataConsumer->finish();
142  }
143 
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:
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:
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 
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 
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>
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 
201 static bool topLevelDeclVisitor(void *context, const Decl *D) {
202  IndexingContext &IndexCtx = *static_cast<IndexingContext *>(context);
203  return IndexCtx.indexTopLevelDecl(D);
204 }
205 
206 static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) {
208 }
209 
211  const MacroInfo *MI,
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.
224  return;
225 
229  DataConsumer.handleMacroOccurrence(II, MI, static_cast<unsigned>(Role), Loc);
230 }
231 
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 
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()) {
252  MI->getDefinitionLoc(), DataConsumer);
253  }
254  }
255  }
256  }
257  }
258 }
259 
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 
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>
292  return std::make_unique<IndexPPCallbacks>(
293  std::make_shared<IndexingContext>(Opts, Consumer));
294 }
295 
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 }
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
static void indexPreprocessorModuleMacros(Preprocessor &PP, serialization::ModuleFile &Mod, IndexDataConsumer &DataConsumer)
static void indexPreprocessorMacros(Preprocessor &PP, IndexDataConsumer &DataConsumer)
static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx)
static void indexPreprocessorMacro(const IdentifierInfo *II, const MacroInfo *MI, MacroDirective::Kind DirectiveKind, SourceLocation Loc, IndexDataConsumer &DataConsumer)
static bool topLevelDeclVisitor(void *context, const Decl *D)
Defines the PPCallbacks interface.
Defines the clang::Preprocessor interface.
SourceRange Range
Definition: SemaObjC.cpp:754
SourceLocation Loc
Definition: SemaObjC.cpp:755
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
Abstract base class to use for AST consumer-based frontend actions.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:366
llvm::iterator_range< ModuleDeclIterator > getModuleFileLevelDecls(ModuleFile &Mod)
Definition: ASTReader.cpp:6231
Preprocessor & getPreprocessor() const
Retrieve the preprocessor.
Definition: ASTReader.h:1777
ASTContext & getContext()
Retrieve the AST context that this AST reader supplements.
Definition: ASTReader.h:2377
Utility class for loading a ASTContext from an AST file.
Definition: ASTUnit.h:89
std::shared_ptr< Preprocessor > getPreprocessorPtr() const
Definition: ASTUnit.h:440
const ASTContext & getASTContext() const
Definition: ASTUnit.h:442
const Preprocessor & getPreprocessor() const
Definition: ASTUnit.h:438
bool visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn)
Iterate over local declarations (locally parsed if this is a parsed source file or the loaded declara...
Definition: ASTUnit.cpp:2636
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
std::shared_ptr< Preprocessor > getPreprocessorPtr()
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
One of these records is kept for each identifier that is lexed.
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
Definition: MacroArgs.h:30
A description of the current definition of a macro.
Definition: MacroInfo.h:590
MacroInfo * getMacroInfo() const
Get the MacroInfo that should be used for this definition.
Definition: MacroInfo.h:606
Encapsulates changes to the "macros namespace" (the location where the macro name became active,...
Definition: MacroInfo.h:313
const MacroInfo * getMacroInfo() const
Definition: MacroInfo.h:416
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition: PPCallbacks.h:35
virtual void Elifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD)
Hook called whenever an #elifndef branch is taken.
Definition: PPCallbacks.h:411
virtual void Elifdef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD)
Hook called whenever an #elifdef branch is taken.
Definition: PPCallbacks.h:387
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
llvm::iterator_range< macro_iterator > macros(bool IncludeExternalMacros=true) const
ArrayRef< ModuleMacro * > getLeafModuleMacros(const IdentifierInfo *II) const
Get the list of leaf (non-overridden) module macros for a name.
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:132
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:187
virtual void setPreprocessor(std::shared_ptr< Preprocessor > PP)
virtual bool handleMacroOccurrence(const IdentifierInfo *Name, const MacroInfo *MI, SymbolRoleSet Roles, SourceLocation Loc)
virtual void initialize(ASTContext &Ctx)
bool indexTopLevelDecl(const Decl *D)
Definition: IndexDecl.cpp:805
void setASTContext(ASTContext &ctx)
Information about a module that has been loaded by the ASTReader.
Definition: ModuleFile.h:124
FileEntryRef File
The file entry for the module file.
Definition: ModuleFile.h:179
DirectiveKind
Represents the kind of preprocessor directive or a module declaration that is tracked by the scanner ...
std::unique_ptr< PPCallbacks > indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts)
Creates a PPCallbacks that indexes macros and feeds macros to Consumer.
void indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, ArrayRef< const Decl * > Decls, IndexDataConsumer &DataConsumer, IndexingOptions Opts)
Recursively indexes Decls.
void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, IndexDataConsumer &DataConsumer, IndexingOptions Opts)
Recursively indexes all top-level decls in the module.
std::unique_ptr< ASTConsumer > createIndexingASTConsumer(std::shared_ptr< IndexDataConsumer > DataConsumer, const IndexingOptions &Opts, std::shared_ptr< Preprocessor > PP)
Creates an ASTConsumer that indexes all symbols (macros and AST decls).
std::unique_ptr< FrontendAction > createIndexingAction(std::shared_ptr< IndexDataConsumer > DataConsumer, const IndexingOptions &Opts)
Creates a frontend action that indexes all symbols (macros and AST decls).
void indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, IndexingOptions Opts)
Recursively indexes all decls in the AST.
The JSON file list parser is used to communicate input to InstallAPI.
Definition: Format.h:5433
#define bool
Definition: stdbool.h:24
std::function< bool(const Decl *)> ShouldTraverseDecl