clang 22.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"
11#include "clang/AST/Attr.h"
12#include "clang/AST/DeclObjC.h"
18
19using namespace clang;
20using namespace index;
21
22static bool isGeneratedDecl(const Decl *D) {
23 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
24 return attr->getGeneratedDeclaration();
25 }
26 return false;
27}
28
30 IndexDataConsumer &DataConsumer)
31 : IndexOpts(IndexOpts), DataConsumer(DataConsumer) {}
32
34
36 Ctx = &ctx;
37 Resolver = Ctx ? std::make_unique<HeuristicResolver>(*Ctx) : nullptr;
38}
39
41 return !isGeneratedDecl(D);
42}
43
45 return Ctx->getLangOpts();
46}
47
49 return IndexOpts.IndexFunctionLocals;
50}
51
53 return IndexOpts.IndexImplicitInstantiation;
54}
55
57 return IndexOpts.IndexParametersInDeclarations;
58}
59
61 return IndexOpts.IndexTemplateParameters;
62}
63
65 SymbolRoleSet Roles,
66 ArrayRef<SymbolRelation> Relations) {
67 return handleDecl(D, D->getLocation(), Roles, Relations);
68}
69
71 SymbolRoleSet Roles,
73 const DeclContext *DC) {
74 if (!DC)
75 DC = D->getDeclContext();
76
77 const Decl *OrigD = D;
78 if (isa<ObjCPropertyImplDecl>(D)) {
79 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
80 }
81 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
82 Roles, Relations,
83 nullptr, OrigD, DC);
84}
85
87 const NamedDecl *Parent,
88 const DeclContext *DC,
89 SymbolRoleSet Roles,
91 const Expr *RefE) {
93 return true;
94
96 (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
97 isa<TemplateTemplateParmDecl>(D))) {
98 return true;
99 }
100 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
101 RefE, nullptr, DC);
102}
103
104static void reportModuleReferences(const Module *Mod,
106 const ImportDecl *ImportD,
107 IndexDataConsumer &DataConsumer) {
108 if (!Mod)
109 return;
110 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
111 DataConsumer);
112 DataConsumer.handleModuleOccurrence(
113 ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
114}
115
117 if (ImportD->isInvalidDecl())
118 return true;
119
121 auto IdLocs = ImportD->getIdentifierLocs();
122 if (!IdLocs.empty())
123 Loc = IdLocs.back();
124 else
125 Loc = ImportD->getLocation();
126
128 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
129 if (FID.isInvalid())
130 return true;
131
132 bool Invalid = false;
133 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
134 if (Invalid || !SEntry.isFile())
135 return true;
136
137 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
138 switch (IndexOpts.SystemSymbolFilter) {
140 return true;
143 break;
144 }
145 }
146
147 const Module *Mod = ImportD->getImportedModule();
148 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
149 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
150 DataConsumer);
151 }
152
154 if (ImportD->isImplicit())
155 Roles |= (unsigned)SymbolRole::Implicit;
156
157 return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
158}
159
163 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
164 TKind = SD->getSpecializationKind();
165 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
166 TKind = FD->getTemplateSpecializationKind();
167 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
168 TKind = VD->getTemplateSpecializationKind();
169 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
170 if (RD->getInstantiatedFromMemberClass())
171 TKind = RD->getTemplateSpecializationKind();
172 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
173 if (ED->getInstantiatedFromMemberEnum())
174 TKind = ED->getTemplateSpecializationKind();
175 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
176 isa<EnumConstantDecl>(D)) {
177 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
179 }
180 switch (TKind) {
181 case TSK_Undeclared:
182 // Instantiation maybe not happen yet when we see a SpecializationDecl,
183 // e.g. when the type doesn't need to be complete, we still treat it as an
184 // instantiation as we'd like to keep the canonicalized result consistent.
185 return isa<ClassTemplateSpecializationDecl>(D);
187 return false;
191 return true;
192 }
193 llvm_unreachable("invalid TemplateSpecializationKind");
194}
195
196bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
197 if (isa<ObjCInterfaceDecl>(D))
198 return false;
199 if (isa<ObjCCategoryDecl>(D))
200 return false;
201 if (isa<ObjCIvarDecl>(D))
202 return false;
203 if (isa<ObjCMethodDecl>(D))
204 return false;
205 if (isa<ImportDecl>(D))
206 return false;
207 return true;
208}
209
210static const CXXRecordDecl *
212 if (const auto *CTSD =
213 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
214 return CTSD->getTemplateInstantiationPattern();
215 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
217 return nullptr;
218}
219
222 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
223 const auto *Template = SD->getTemplateInstantiationPattern();
224 if (Template)
225 return Template;
226 // Fallback to primary template if no instantiation is available yet (e.g.
227 // the type doesn't need to be complete).
228 return SD->getSpecializedTemplate()->getTemplatedDecl();
229 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
230 return FD->getTemplateInstantiationPattern();
231 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
232 return VD->getTemplateInstantiationPattern();
233 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
234 return RD->getInstantiatedFromMemberClass();
235 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
236 return ED->getInstantiatedFromMemberEnum();
237 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
238 const auto *ND = cast<NamedDecl>(D);
239 if (const CXXRecordDecl *Pattern =
241 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
242 if (BaseND->isImplicit())
243 continue;
244 if (BaseND->getKind() == ND->getKind())
245 return BaseND;
246 }
247 }
248 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
249 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
250 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
251 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
252 return BaseECD;
253 }
254 }
255 }
256 return nullptr;
257}
258
259static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
260 if (auto VD = dyn_cast<VarDecl>(D))
261 return VD->isThisDeclarationADefinition(Ctx);
262
263 if (auto FD = dyn_cast<FunctionDecl>(D))
264 return FD->isThisDeclarationADefinition();
265
266 if (auto TD = dyn_cast<TagDecl>(D))
267 return TD->isThisDeclarationADefinition();
268
269 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
270 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
271
272 if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||
273 isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||
274 isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))
275 return true;
276
277 return false;
278}
279
280/// Whether the given NamedDecl should be skipped because it has no name.
281static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
282 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
283 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
284}
285
286static const Decl *adjustParent(const Decl *Parent) {
287 if (!Parent)
288 return nullptr;
289 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
290 if (isa<TranslationUnitDecl>(Parent))
291 return nullptr;
292 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
293 continue;
294 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
295 if (NS->isAnonymousNamespace())
296 continue;
297 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
298 if (RD->isAnonymousStructOrUnion())
299 continue;
300 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
302 continue;
303 }
304 return Parent;
305 }
306}
307
308static const Decl *getCanonicalDecl(const Decl *D) {
309 D = D->getCanonicalDecl();
310 if (auto TD = dyn_cast<TemplateDecl>(D)) {
311 if (auto TTD = TD->getTemplatedDecl()) {
312 D = TTD;
313 assert(D->isCanonicalDecl());
314 }
315 }
316
317 return D;
318}
319
321 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
322 if (!IsRef)
323 return true;
324
325 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
326 bool accept = false;
327 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
328 switch (r) {
335 accept = true;
336 return false;
340 case SymbolRole::Read:
342 case SymbolRole::Call:
352 return true;
353 }
354 llvm_unreachable("Unsupported SymbolRole value!");
355 });
356 return accept;
357 };
358
359 for (auto &Rel : Relations) {
360 if (acceptForRelation(Rel.Roles))
361 return true;
362 }
363
364 return false;
365}
366
367bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
368 bool IsRef, const Decl *Parent,
369 SymbolRoleSet Roles,
370 ArrayRef<SymbolRelation> Relations,
371 const Expr *OrigE,
372 const Decl *OrigD,
373 const DeclContext *ContainerDC) {
374 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
375 return true;
376 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
377 return true;
378
380 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
381 if (FID.isInvalid())
382 return true;
383
384 bool Invalid = false;
385 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
386 if (Invalid || !SEntry.isFile())
387 return true;
388
389 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
390 switch (IndexOpts.SystemSymbolFilter) {
392 return true;
394 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
395 return true;
396 break;
398 break;
399 }
400 }
401
402 if (!OrigD)
403 OrigD = D;
404
406 if (!IsRef)
407 return true;
409 if (!D)
410 return true;
412 }
413
414 if (IsRef)
416 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
417 Roles |= (unsigned)SymbolRole::Definition;
418 else
420
423 if (Parent)
425
426 SmallVector<SymbolRelation, 6> FinalRelations;
427 FinalRelations.reserve(Relations.size()+1);
428
429 auto addRelation = [&](SymbolRelation Rel) {
430 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
431 return Elem.RelatedSymbol == Rel.RelatedSymbol;
432 });
433 if (It != FinalRelations.end()) {
434 It->Roles |= Rel.Roles;
435 } else {
436 FinalRelations.push_back(Rel);
437 }
438 Roles |= Rel.Roles;
439 };
440
441 if (Parent) {
442 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
443 addRelation(SymbolRelation{
445 Parent
446 });
447 } else {
448 addRelation(SymbolRelation{
450 Parent
451 });
452 }
453 }
454
455 for (auto &Rel : Relations) {
456 addRelation(SymbolRelation(Rel.Roles,
457 Rel.RelatedSymbol->getCanonicalDecl()));
458 }
459
460 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
461 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
462}
463
466 const MacroInfo &MI) {
467 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
468 return;
470 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
471}
472
475 const MacroInfo &MI) {
476 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
477 return;
479 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
480}
481
484 const MacroInfo &MI) {
485 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
486 return;
488 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
489}
490
491bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
493 if (!IndexOpts.IndexMacros)
494 return false;
495
496 switch (IndexOpts.SystemSymbolFilter) {
498 break;
500 if (!IsRef)
501 return true;
502 break;
504 return true;
505 }
506
508 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
509 if (FID.isInvalid())
510 return false;
511
512 bool Invalid = false;
513 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
514 if (Invalid || !SEntry.isFile())
515 return false;
516
517 return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
518}
Defines the clang::ASTContext interface.
NodeId Parent
Definition: ASTDiff.cpp:191
DynTypedNode Node
const Decl * D
Defines the C++ template declaration subclasses.
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 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)
static const CXXRecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D)
static const Decl * getCanonicalDecl(const Decl *D)
#define SM(sm)
Definition: OffloadArch.cpp:16
SourceLocation Loc
Definition: SemaObjC.cpp:754
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:188
SourceManager & getSourceManager()
Definition: ASTContext.h:801
const LangOptions & getLangOpts() const
Definition: ASTContext.h:894
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:2020
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:2075
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:1449
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
T * getAttr() const
Definition: DeclBase.h:573
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:593
bool isCanonicalDecl() const
Whether this particular Decl is a canonical one.
Definition: DeclBase.h:984
bool isInvalidDecl() const
Definition: DeclBase.h:588
SourceLocation getLocation() const
Definition: DeclBase.h:439
DeclContext * getDeclContext()
Definition: DeclBase.h:448
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclBase.h:978
bool isEmpty() const
Evaluates true when this declaration name is empty.
Represents an enum.
Definition: Decl.h:4004
EnumDecl * getInstantiatedFromMemberEnum() const
Returns the enumeration (declared within the template) from which this enumeration type was instantia...
Definition: Decl.cpp:5033
This represents one expression.
Definition: Expr.h:112
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:1999
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:5015
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:5938
Module * getImportedModule() const
Retrieve the module that was imported by the import declaration.
Definition: Decl.h:5073
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:434
Encapsulates the data about a macro definition (e.g.
Definition: MacroInfo.h:39
Describes a module or submodule.
Definition: Module.h:144
Module * Parent
The parent of this module.
Definition: Module.h:193
This represents a decl that may have a name.
Definition: Decl.h:273
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:339
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)
void setASTContext(ASTContext &ctx)
bool shouldIndexImplicitInstantiation() const
bool importedModule(const ImportDecl *ImportD)
bool handleDecl(const Decl *D, SymbolRoleSet Roles=SymbolRoleSet(), ArrayRef< SymbolRelation > Relations={})
bool shouldIndex(const Decl *D)
bool handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, SymbolRoleSet Roles=SymbolRoleSet(), ArrayRef< SymbolRelation > Relations={}, const Expr *RefE=nullptr)
bool shouldIndexFunctionLocalSymbols() const
void handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MD)
IndexingContext(IndexingOptions IndexOpts, IndexDataConsumer &DataConsumer)
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)
const internal::VariadicAllOfMatcher< Attr > attr
Matches attributes.
SymbolRole
Set of roles that are attributed to symbol occurrences.
Definition: IndexSymbol.h:103
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.
@ Template
We are parsing a template declaration.
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition: Specifiers.h:188
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition: Specifiers.h:206
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition: Specifiers.h:202
@ TSK_ExplicitSpecialization
This template specialization was declared or defined by an explicit specialization (C++ [temp....
Definition: Specifiers.h:198
@ TSK_ImplicitInstantiation
This template specialization was implicitly instantiated from a template.
Definition: Specifiers.h:194
@ TSK_Undeclared
This template specialization was formed from a template-id but has not yet been declared,...
Definition: Specifiers.h:191
SystemSymbolFilterKind SystemSymbolFilter
Represents a relation to another symbol for a symbol occurrence.
Definition: IndexSymbol.h:137