clang  14.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,
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
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 }
clang::ASTUnit
Utility class for loading a ASTContext from an AST file.
Definition: ASTUnit.h:89
clang::index::IndexingOptions::IndexMacrosInPreprocessor
bool IndexMacrosInPreprocessor
Definition: IndexingOptions.h:35
clang::ASTReader::getContext
ASTContext & getContext()
Retrieve the AST context that this AST reader supplements.
Definition: ASTReader.h:2263
clang::index::indexTopLevelDecls
void indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, ArrayRef< const Decl * > Decls, IndexDataConsumer &DataConsumer, IndexingOptions Opts)
Recursively indexes Decls.
Definition: IndexingAction.cpp:273
IndexingContext.h
topLevelDeclVisitor
static bool topLevelDeclVisitor(void *context, const Decl *D)
Definition: IndexingAction.cpp:201
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:212
clang::CompilerInstance::getPreprocessorPtr
std::shared_ptr< Preprocessor > getPreprocessorPtr()
Definition: CompilerInstance.h:449
clang::index::indexModuleFile
void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, IndexDataConsumer &DataConsumer, IndexingOptions Opts)
Recursively indexes all top-level decls in the module.
Definition: IndexingAction.cpp:296
clang::MacroDefinition
A description of the current definition of a macro.
Definition: MacroInfo.h:564
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::PPCallbacks
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition: PPCallbacks.h:35
IndexingAction.h
clang::ASTUnit::visitLocalTopLevelDecls
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:2587
clang::index::IndexDataConsumer::setPreprocessor
virtual void setPreprocessor(std::shared_ptr< Preprocessor > PP)
Definition: IndexDataConsumer.h:39
clang::Token::getIdentifierInfo
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:179
clang::MacroArgs
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
Definition: MacroArgs.h:29
clang::index::SymbolRole::Definition
@ Definition
clang::ASTReader::getPreprocessor
Preprocessor & getPreprocessor() const
Retrieve the preprocessor.
Definition: ASTReader.h:1695
clang::index::IndexDataConsumer
Definition: IndexDataConsumer.h:26
clang::MacroInfo
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
FrontendAction.h
clang::index::createIndexingAction
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).
Definition: IndexingAction.cpp:195
clang::Token
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
clang::index::indexMacrosCallback
std::unique_ptr< PPCallbacks > indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts)
Creates a PPCallbacks that indexes macros and feeds macros to Consumer.
Definition: IndexingAction.cpp:291
Preprocessor.h
clang::ASTUnit::getASTContext
const ASTContext & getASTContext() const
Definition: ASTUnit.h:439
clang::MacroDefinition::getMacroInfo
MacroInfo * getMacroInfo() const
Get the MacroInfo that should be used for this definition.
Definition: MacroInfo.h:580
clang::MacroDirective::MD_Visibility
@ MD_Visibility
Definition: MacroInfo.h:295
clang::ASTUnit::getPreprocessorPtr
std::shared_ptr< Preprocessor > getPreprocessorPtr() const
Definition: ASTUnit.h:437
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:212
clang::PPCallbacks::Elifdef
virtual void Elifdef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD)
Hook called whenever an #elifdef branch is taken.
Definition: PPCallbacks.h:373
clang::ASTConsumer
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
clang::PPCallbacks::Elifndef
virtual void Elifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD)
Hook called whenever an #elifndef branch is taken.
Definition: PPCallbacks.h:397
clang::index::IndexDataConsumer::initialize
virtual void initialize(ASTContext &Ctx)
Definition: IndexDataConsumer.h:37
clang::MacroDirective::Kind
Kind
Definition: MacroInfo.h:292
bool
#define bool
Definition: stdbool.h:15
clang::ASTReader::getModuleFileLevelDecls
llvm::iterator_range< ModuleDeclIterator > getModuleFileLevelDecls(ModuleFile &Mod)
Definition: ASTReader.cpp:5916
clang::index::IndexDataConsumer::handleMacroOccurrence
virtual bool handleMacroOccurrence(const IdentifierInfo *Name, const MacroInfo *MI, SymbolRoleSet Roles, SourceLocation Loc)
Definition: IndexDataConsumer.h:49
clang::index::createIndexingASTConsumer
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).
Definition: IndexingAction.cpp:179
clang::ASTUnit::getPreprocessor
const Preprocessor & getPreprocessor() const
Definition: ASTUnit.h:435
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:74
clang::index::SymbolRole::Undefinition
@ Undefinition
indexTranslationUnit
static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx)
Definition: IndexingAction.cpp:206
clang::serialization::ModuleFile::File
OptionalFileEntryRefDegradesToFileEntryPtr File
The file entry for the module file.
Definition: ModuleFile.h:167
clang::index::IndexingContext
Definition: IndexingContext.h:38
clang::index::IndexingContext::setASTContext
void setASTContext(ASTContext &ctx)
Definition: IndexingContext.h:50
clang::transformer::EditKind::Range
@ Range
clang::index
Definition: CommentToXML.h:22
indexPreprocessorMacro
static void indexPreprocessorMacro(const IdentifierInfo *II, const MacroInfo *MI, MacroDirective::Kind DirectiveKind, SourceLocation Loc, IndexDataConsumer &DataConsumer)
Definition: IndexingAction.cpp:210
llvm::ArrayRef
Definition: LLVM.h:34
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
IndexDataConsumer.h
clang::DeclGroupRef
Definition: DeclGroup.h:51
clang::index::IndexingOptions::ShouldTraverseDecl
std::function< bool(const Decl *)> ShouldTraverseDecl
Definition: IndexingOptions.h:44
clang::index::IndexingOptions
Definition: IndexingOptions.h:20
indexPreprocessorModuleMacros
static void indexPreprocessorModuleMacros(Preprocessor &PP, serialization::ModuleFile &Mod, IndexDataConsumer &DataConsumer)
Definition: IndexingAction.cpp:242
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
clang::Token::getLocation
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:126
clang::ASTReader
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:342
clang::MacroDirective::MD_Define
@ MD_Define
Definition: MacroInfo.h:293
std
Definition: Format.h:4034
clang
Definition: CalledOnceCheck.h:17
indexPreprocessorMacros
static void indexPreprocessorMacros(Preprocessor &PP, IndexDataConsumer &DataConsumer)
Definition: IndexingAction.cpp:232
PPCallbacks.h
clang::MacroDirective
Encapsulates changes to the "macros namespace" (the location where the macro name became active,...
Definition: MacroInfo.h:290
clang::MacroDirective::getMacroInfo
const MacroInfo * getMacroInfo() const
Definition: MacroInfo.h:390
ASTReader.h
clang::Preprocessor::getLeafModuleMacros
ArrayRef< ModuleMacro * > getLeafModuleMacros(const IdentifierInfo *II) const
Get the list of leaf (non-overridden) module macros for a name.
Definition: Preprocessor.h:1195
clang::index::IndexingContext::indexTopLevelDecl
bool indexTopLevelDecl(const Decl *D)
Definition: IndexDecl.cpp:771
clang::Preprocessor::macros
llvm::iterator_range< macro_iterator > macros(bool IncludeExternalMacros=true) const
Definition: Preprocessor.h:1219
CompilerInstance.h
clang::index::indexASTUnit
void indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, IndexingOptions Opts)
Recursively indexes all decls in the AST.
Definition: IndexingAction.cpp:260
clang::ASTFrontendAction
Abstract base class to use for AST consumer-based frontend actions.
Definition: FrontendAction.h:243
clang::Preprocessor
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:130
clang::index::IndexDataConsumer::finish
virtual void finish()
Definition: IndexDataConsumer.h:66
clang::serialization::ModuleFile
Information about a module that has been loaded by the ASTReader.
Definition: ModuleFile.h:111
MultiplexConsumer.h