clang  19.0.0git
IndexingContext.cpp
Go to the documentation of this file.
1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
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 "IndexingContext.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Attr.h"
12 #include "clang/AST/DeclObjC.h"
13 #include "clang/AST/DeclTemplate.h"
17 
18 using namespace clang;
19 using namespace index;
20 
21 static bool isGeneratedDecl(const Decl *D) {
22  if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23  return attr->getGeneratedDeclaration();
24  }
25  return false;
26 }
27 
29  return !isGeneratedDecl(D);
30 }
31 
33  return Ctx->getLangOpts();
34 }
35 
37  return IndexOpts.IndexFunctionLocals;
38 }
39 
41  return IndexOpts.IndexImplicitInstantiation;
42 }
43 
45  return IndexOpts.IndexParametersInDeclarations;
46 }
47 
49  return IndexOpts.IndexTemplateParameters;
50 }
51 
53  SymbolRoleSet Roles,
54  ArrayRef<SymbolRelation> Relations) {
55  return handleDecl(D, D->getLocation(), Roles, Relations);
56 }
57 
59  SymbolRoleSet Roles,
60  ArrayRef<SymbolRelation> Relations,
61  const DeclContext *DC) {
62  if (!DC)
63  DC = D->getDeclContext();
64 
65  const Decl *OrigD = D;
66  if (isa<ObjCPropertyImplDecl>(D)) {
67  D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
68  }
69  return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
70  Roles, Relations,
71  nullptr, OrigD, DC);
72 }
73 
75  const NamedDecl *Parent,
76  const DeclContext *DC,
77  SymbolRoleSet Roles,
78  ArrayRef<SymbolRelation> Relations,
79  const Expr *RefE) {
81  return true;
82 
84  (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
85  isa<TemplateTemplateParmDecl>(D))) {
86  return true;
87  }
88  return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
89  RefE, nullptr, DC);
90 }
91 
92 static void reportModuleReferences(const Module *Mod,
94  const ImportDecl *ImportD,
95  IndexDataConsumer &DataConsumer) {
96  if (!Mod)
97  return;
98  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
99  DataConsumer);
100  DataConsumer.handleModuleOccurrence(
101  ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
102 }
103 
105  if (ImportD->isInvalidDecl())
106  return true;
107 
109  auto IdLocs = ImportD->getIdentifierLocs();
110  if (!IdLocs.empty())
111  Loc = IdLocs.back();
112  else
113  Loc = ImportD->getLocation();
114 
116  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
117  if (FID.isInvalid())
118  return true;
119 
120  bool Invalid = false;
121  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
122  if (Invalid || !SEntry.isFile())
123  return true;
124 
125  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
126  switch (IndexOpts.SystemSymbolFilter) {
128  return true;
131  break;
132  }
133  }
134 
135  const Module *Mod = ImportD->getImportedModule();
136  if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
137  reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
138  DataConsumer);
139  }
140 
142  if (ImportD->isImplicit())
143  Roles |= (unsigned)SymbolRole::Implicit;
144 
145  return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
146 }
147 
151  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
152  TKind = SD->getSpecializationKind();
153  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
154  TKind = FD->getTemplateSpecializationKind();
155  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
156  TKind = VD->getTemplateSpecializationKind();
157  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
158  if (RD->getInstantiatedFromMemberClass())
159  TKind = RD->getTemplateSpecializationKind();
160  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
161  if (ED->getInstantiatedFromMemberEnum())
162  TKind = ED->getTemplateSpecializationKind();
163  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
164  isa<EnumConstantDecl>(D)) {
165  if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
167  }
168  switch (TKind) {
169  case TSK_Undeclared:
170  // Instantiation maybe not happen yet when we see a SpecializationDecl,
171  // e.g. when the type doesn't need to be complete, we still treat it as an
172  // instantiation as we'd like to keep the canonicalized result consistent.
173  return isa<ClassTemplateSpecializationDecl>(D);
175  return false;
179  return true;
180  }
181  llvm_unreachable("invalid TemplateSpecializationKind");
182 }
183 
184 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
185  if (isa<ObjCInterfaceDecl>(D))
186  return false;
187  if (isa<ObjCCategoryDecl>(D))
188  return false;
189  if (isa<ObjCIvarDecl>(D))
190  return false;
191  if (isa<ObjCMethodDecl>(D))
192  return false;
193  if (isa<ImportDecl>(D))
194  return false;
195  return true;
196 }
197 
198 static const CXXRecordDecl *
200  if (const auto *CTSD =
201  dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
202  return CTSD->getTemplateInstantiationPattern();
203  else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
204  return RD->getInstantiatedFromMemberClass();
205  return nullptr;
206 }
207 
210  SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
211  const auto *Template = SD->getTemplateInstantiationPattern();
212  if (Template)
213  return Template;
214  // Fallback to primary template if no instantiation is available yet (e.g.
215  // the type doesn't need to be complete).
216  return SD->getSpecializedTemplate()->getTemplatedDecl();
217  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
218  return FD->getTemplateInstantiationPattern();
219  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
220  return VD->getTemplateInstantiationPattern();
221  } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
222  return RD->getInstantiatedFromMemberClass();
223  } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
224  return ED->getInstantiatedFromMemberEnum();
225  } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
226  const auto *ND = cast<NamedDecl>(D);
227  if (const CXXRecordDecl *Pattern =
229  for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
230  if (BaseND->isImplicit())
231  continue;
232  if (BaseND->getKind() == ND->getKind())
233  return BaseND;
234  }
235  }
236  } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
237  if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
238  if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
239  for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
240  return BaseECD;
241  }
242  }
243  }
244  return nullptr;
245 }
246 
247 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
248  if (auto VD = dyn_cast<VarDecl>(D))
249  return VD->isThisDeclarationADefinition(Ctx);
250 
251  if (auto FD = dyn_cast<FunctionDecl>(D))
252  return FD->isThisDeclarationADefinition();
253 
254  if (auto TD = dyn_cast<TagDecl>(D))
255  return TD->isThisDeclarationADefinition();
256 
257  if (auto MD = dyn_cast<ObjCMethodDecl>(D))
258  return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
259 
260  if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||
261  isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||
262  isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))
263  return true;
264 
265  return false;
266 }
267 
268 /// Whether the given NamedDecl should be skipped because it has no name.
269 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
270  return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
271  !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
272 }
273 
274 static const Decl *adjustParent(const Decl *Parent) {
275  if (!Parent)
276  return nullptr;
277  for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
278  if (isa<TranslationUnitDecl>(Parent))
279  return nullptr;
280  if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
281  continue;
282  if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
283  if (NS->isAnonymousNamespace())
284  continue;
285  } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
286  if (RD->isAnonymousStructOrUnion())
287  continue;
288  } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
289  if (shouldSkipNamelessDecl(ND))
290  continue;
291  }
292  return Parent;
293  }
294 }
295 
296 static const Decl *getCanonicalDecl(const Decl *D) {
297  D = D->getCanonicalDecl();
298  if (auto TD = dyn_cast<TemplateDecl>(D)) {
299  if (auto TTD = TD->getTemplatedDecl()) {
300  D = TTD;
301  assert(D->isCanonicalDecl());
302  }
303  }
304 
305  return D;
306 }
307 
309  bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
310  if (!IsRef)
311  return true;
312 
313  auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
314  bool accept = false;
315  applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
316  switch (r) {
323  accept = true;
324  return false;
328  case SymbolRole::Read:
329  case SymbolRole::Write:
330  case SymbolRole::Call:
331  case SymbolRole::Dynamic:
340  return true;
341  }
342  llvm_unreachable("Unsupported SymbolRole value!");
343  });
344  return accept;
345  };
346 
347  for (auto &Rel : Relations) {
348  if (acceptForRelation(Rel.Roles))
349  return true;
350  }
351 
352  return false;
353 }
354 
355 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
356  bool IsRef, const Decl *Parent,
357  SymbolRoleSet Roles,
358  ArrayRef<SymbolRelation> Relations,
359  const Expr *OrigE,
360  const Decl *OrigD,
361  const DeclContext *ContainerDC) {
362  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
363  return true;
364  if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
365  return true;
366 
368  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
369  if (FID.isInvalid())
370  return true;
371 
372  bool Invalid = false;
373  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
374  if (Invalid || !SEntry.isFile())
375  return true;
376 
377  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
378  switch (IndexOpts.SystemSymbolFilter) {
380  return true;
382  if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
383  return true;
384  break;
386  break;
387  }
388  }
389 
390  if (!OrigD)
391  OrigD = D;
392 
394  if (!IsRef)
395  return true;
397  if (!D)
398  return true;
400  }
401 
402  if (IsRef)
404  else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
405  Roles |= (unsigned)SymbolRole::Definition;
406  else
408 
409  D = getCanonicalDecl(D);
411  if (Parent)
413 
414  SmallVector<SymbolRelation, 6> FinalRelations;
415  FinalRelations.reserve(Relations.size()+1);
416 
417  auto addRelation = [&](SymbolRelation Rel) {
418  auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
419  return Elem.RelatedSymbol == Rel.RelatedSymbol;
420  });
421  if (It != FinalRelations.end()) {
422  It->Roles |= Rel.Roles;
423  } else {
424  FinalRelations.push_back(Rel);
425  }
426  Roles |= Rel.Roles;
427  };
428 
429  if (Parent) {
430  if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
431  addRelation(SymbolRelation{
433  Parent
434  });
435  } else {
436  addRelation(SymbolRelation{
438  Parent
439  });
440  }
441  }
442 
443  for (auto &Rel : Relations) {
444  addRelation(SymbolRelation(Rel.Roles,
445  Rel.RelatedSymbol->getCanonicalDecl()));
446  }
447 
448  IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
449  return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
450 }
451 
454  const MacroInfo &MI) {
455  if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
456  return;
458  DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
459 }
460 
463  const MacroInfo &MI) {
464  if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
465  return;
467  DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
468 }
469 
472  const MacroInfo &MI) {
473  if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
474  return;
476  DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
477 }
478 
479 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
481  if (!IndexOpts.IndexMacros)
482  return false;
483 
484  switch (IndexOpts.SystemSymbolFilter) {
486  break;
488  if (!IsRef)
489  return true;
490  break;
492  return true;
493  }
494 
496  FileID FID = SM.getFileID(SM.getFileLoc(Loc));
497  if (FID.isInvalid())
498  return false;
499 
500  bool Invalid = false;
501  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
502  if (Invalid || !SEntry.isFile())
503  return false;
504 
505  return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
506 }
Defines the clang::ASTContext interface.
NodeId Parent
Definition: ASTDiff.cpp:191
DynTypedNode Node
#define SM(sm)
Definition: Cuda.cpp:83
Defines the C++ template declaration subclasses.
static const Decl * getCanonicalDecl(const Decl *D)
static bool shouldSkipNamelessDecl(const NamedDecl *ND)
Whether the given NamedDecl should be skipped because it has no name.
static const Decl * adjustParent(const Decl *Parent)
static const CXXRecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D)
static void reportModuleReferences(const Module *Mod, ArrayRef< SourceLocation > IdLocs, const ImportDecl *ImportD, IndexDataConsumer &DataConsumer)
static bool isGeneratedDecl(const Decl *D)
static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx)
static bool shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations)
static const Decl * adjustTemplateImplicitInstantiation(const Decl *D)
SourceLocation Loc
Definition: SemaObjC.cpp:755
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
SourceManager & getSourceManager()
Definition: ASTContext.h:708
const LangOptions & getLangOpts() const
Definition: ASTContext.h:778
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
CXXRecordDecl * getInstantiatedFromMemberClass() const
If this record is an instantiation of a member class, retrieves the member class from which it was in...
Definition: DeclCXX.cpp:1876
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:1930
Represents a class template specialization, which refers to a class template with a given set of temp...
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:599
bool isCanonicalDecl() const
Whether this particular Decl is a canonical one.
Definition: DeclBase.h:974
bool isInvalidDecl() const
Definition: DeclBase.h:594
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:968
SourceLocation getLocation() const
Definition: DeclBase.h:445
T * getAttr() const
Definition: DeclBase.h:579
DeclContext * getDeclContext()
Definition: DeclBase.h:454
bool isEmpty() const
Evaluates true when this declaration name is empty.
Represents an enum.
Definition: Decl.h:3870
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:4942
This represents one expression.
Definition: Expr.h:110
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isInvalid() const
Represents a function declaration or definition.
Definition: Decl.h:1972
One of these records is kept for each identifier that is lexed.
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4802
Module * getImportedModule() const
Retrieve the module that was imported by the import declaration.
Definition: Decl.h:4860
ArrayRef< SourceLocation > getIdentifierLocs() const
Retrieves the locations of each of the identifiers that make up the complete module name in the impor...
Definition: Decl.cpp:5733
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:482
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
Describes a module or submodule.
Definition: Module.h:105
Module * Parent
The parent of this module.
Definition: Module.h:154
This represents a decl that may have a name.
Definition: Decl.h:249
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:315
Encodes a location in the source.
This class handles loading and caching of source files into memory.
CharacteristicKind getFileCharacteristic() const
Return whether this is a system header or not.
This is a discriminated union of FileInfo and ExpansionInfo.
const FileInfo & getFile() const
virtual bool handleDeclOccurrence(const Decl *D, SymbolRoleSet Roles, ArrayRef< SymbolRelation > Relations, SourceLocation Loc, ASTNodeInfo ASTNode)
virtual bool handleMacroOccurrence(const IdentifierInfo *Name, const MacroInfo *MI, SymbolRoleSet Roles, SourceLocation Loc)
virtual bool handleModuleOccurrence(const ImportDecl *ImportD, const Module *Mod, SymbolRoleSet Roles, SourceLocation Loc)
bool shouldIndexImplicitInstantiation() const
bool importedModule(const ImportDecl *ImportD)
bool shouldIndex(const Decl *D)
bool shouldIndexFunctionLocalSymbols() const
void handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MD)
bool handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, SymbolRoleSet Roles=SymbolRoleSet(), ArrayRef< SymbolRelation > Relations=std::nullopt, const Expr *RefE=nullptr)
bool shouldIndexParametersInDeclarations() const
void handleMacroUndefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI)
static bool isTemplateImplicitInstantiation(const Decl *D)
const LangOptions & getLangOpts() const
void handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI)
bool handleDecl(const Decl *D, SymbolRoleSet Roles=SymbolRoleSet(), ArrayRef< SymbolRelation > Relations=std::nullopt)
const internal::VariadicAllOfMatcher< Attr > attr
Matches attributes.
SymbolRole
Set of roles that are attributed to symbol occurrences.
Definition: IndexSymbol.h:102
bool isFunctionLocalSymbol(const Decl *D)
Definition: IndexSymbol.cpp:53
bool applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, llvm::function_ref< bool(SymbolRole)> Fn)
The JSON file list parser is used to communicate input to InstallAPI.
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:185
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition: Specifiers.h:203
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition: Specifiers.h:199
@ TSK_ExplicitSpecialization
This template specialization was declared or defined by an explicit specialization (C++ [temp....
Definition: Specifiers.h:195
@ TSK_ImplicitInstantiation
This template specialization was implicitly instantiated from a template.
Definition: Specifiers.h:191
@ TSK_Undeclared
This template specialization was formed from a template-id but has not yet been declared,...
Definition: Specifiers.h:188
SystemSymbolFilterKind SystemSymbolFilter
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:136