1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Index/IndexDataConsumer.h"
18 using namespace clang
;
19 using namespace index
;
21 static bool isGeneratedDecl(const Decl
*D
) {
22 if (auto *attr
= D
->getAttr
<ExternalSourceSymbolAttr
>()) {
23 return attr
->getGeneratedDeclaration();
28 bool IndexingContext::shouldIndex(const Decl
*D
) {
29 return !isGeneratedDecl(D
);
32 const LangOptions
&IndexingContext::getLangOpts() const {
33 return Ctx
->getLangOpts();
36 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
37 return IndexOpts
.IndexFunctionLocals
;
40 bool IndexingContext::shouldIndexImplicitInstantiation() const {
41 return IndexOpts
.IndexImplicitInstantiation
;
44 bool IndexingContext::shouldIndexParametersInDeclarations() const {
45 return IndexOpts
.IndexParametersInDeclarations
;
48 bool IndexingContext::shouldIndexTemplateParameters() const {
49 return IndexOpts
.IndexTemplateParameters
;
52 bool IndexingContext::handleDecl(const Decl
*D
,
54 ArrayRef
<SymbolRelation
> Relations
) {
55 return handleDecl(D
, D
->getLocation(), Roles
, Relations
);
58 bool IndexingContext::handleDecl(const Decl
*D
, SourceLocation Loc
,
60 ArrayRef
<SymbolRelation
> Relations
,
61 const DeclContext
*DC
) {
63 DC
= D
->getDeclContext();
65 const Decl
*OrigD
= D
;
66 if (isa
<ObjCPropertyImplDecl
>(D
)) {
67 D
= cast
<ObjCPropertyImplDecl
>(D
)->getPropertyDecl();
69 return handleDeclOccurrence(D
, Loc
, /*IsRef=*/false, cast
<Decl
>(DC
),
74 bool IndexingContext::handleReference(const NamedDecl
*D
, SourceLocation Loc
,
75 const NamedDecl
*Parent
,
76 const DeclContext
*DC
,
78 ArrayRef
<SymbolRelation
> Relations
,
80 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D
))
83 if (!shouldIndexTemplateParameters() &&
84 (isa
<NonTypeTemplateParmDecl
>(D
) || isa
<TemplateTypeParmDecl
>(D
) ||
85 isa
<TemplateTemplateParmDecl
>(D
))) {
88 return handleDeclOccurrence(D
, Loc
, /*IsRef=*/true, Parent
, Roles
, Relations
,
92 static void reportModuleReferences(const Module
*Mod
,
93 ArrayRef
<SourceLocation
> IdLocs
,
94 const ImportDecl
*ImportD
,
95 IndexDataConsumer
&DataConsumer
) {
98 reportModuleReferences(Mod
->Parent
, IdLocs
.drop_back(), ImportD
,
100 DataConsumer
.handleModuleOccurrence(
101 ImportD
, Mod
, (SymbolRoleSet
)SymbolRole::Reference
, IdLocs
.back());
104 bool IndexingContext::importedModule(const ImportDecl
*ImportD
) {
105 if (ImportD
->isInvalidDecl())
109 auto IdLocs
= ImportD
->getIdentifierLocs();
113 Loc
= ImportD
->getLocation();
115 SourceManager
&SM
= Ctx
->getSourceManager();
116 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
120 bool Invalid
= false;
121 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
122 if (Invalid
|| !SEntry
.isFile())
125 if (SEntry
.getFile().getFileCharacteristic() != SrcMgr::C_User
) {
126 switch (IndexOpts
.SystemSymbolFilter
) {
127 case IndexingOptions::SystemSymbolFilterKind::None
:
129 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
130 case IndexingOptions::SystemSymbolFilterKind::All
:
135 const Module
*Mod
= ImportD
->getImportedModule();
136 if (!ImportD
->isImplicit() && Mod
->Parent
&& !IdLocs
.empty()) {
137 reportModuleReferences(Mod
->Parent
, IdLocs
.drop_back(), ImportD
,
141 SymbolRoleSet Roles
= (unsigned)SymbolRole::Declaration
;
142 if (ImportD
->isImplicit())
143 Roles
|= (unsigned)SymbolRole::Implicit
;
145 return DataConsumer
.handleModuleOccurrence(ImportD
, Mod
, Roles
, Loc
);
148 bool IndexingContext::isTemplateImplicitInstantiation(const Decl
*D
) {
149 TemplateSpecializationKind TKind
= TSK_Undeclared
;
150 if (const ClassTemplateSpecializationDecl
*
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()))
166 return isTemplateImplicitInstantiation(Parent
);
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
);
174 case TSK_ExplicitSpecialization
:
176 case TSK_ImplicitInstantiation
:
177 case TSK_ExplicitInstantiationDeclaration
:
178 case TSK_ExplicitInstantiationDefinition
:
181 llvm_unreachable("invalid TemplateSpecializationKind");
184 bool IndexingContext::shouldIgnoreIfImplicit(const Decl
*D
) {
185 if (isa
<ObjCInterfaceDecl
>(D
))
187 if (isa
<ObjCCategoryDecl
>(D
))
189 if (isa
<ObjCIvarDecl
>(D
))
191 if (isa
<ObjCMethodDecl
>(D
))
193 if (isa
<ImportDecl
>(D
))
198 static const CXXRecordDecl
*
199 getDeclContextForTemplateInstationPattern(const Decl
*D
) {
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();
208 static const Decl
*adjustTemplateImplicitInstantiation(const Decl
*D
) {
209 if (const ClassTemplateSpecializationDecl
*
210 SD
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
)) {
211 const auto *Template
= SD
->getTemplateInstantiationPattern();
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
=
228 getDeclContextForTemplateInstationPattern(ND
)) {
229 for (const NamedDecl
*BaseND
: Pattern
->lookup(ND
->getDeclName())) {
230 if (BaseND
->isImplicit())
232 if (BaseND
->getKind() == ND
->getKind())
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()))
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
);
251 if (auto FD
= dyn_cast
<FunctionDecl
>(D
))
252 return FD
->isThisDeclarationADefinition();
254 if (auto TD
= dyn_cast
<TagDecl
>(D
))
255 return TD
->isThisDeclarationADefinition();
257 if (auto MD
= dyn_cast
<ObjCMethodDecl
>(D
))
258 return MD
->isThisDeclarationADefinition() || isa
<ObjCImplDecl
>(ContainerDC
);
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
))
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
);
274 static const Decl
*adjustParent(const Decl
*Parent
) {
277 for (;; Parent
= cast
<Decl
>(Parent
->getDeclContext())) {
278 if (isa
<TranslationUnitDecl
>(Parent
))
280 if (isa
<LinkageSpecDecl
>(Parent
) || isa
<BlockDecl
>(Parent
))
282 if (auto NS
= dyn_cast
<NamespaceDecl
>(Parent
)) {
283 if (NS
->isAnonymousNamespace())
285 } else if (auto RD
= dyn_cast
<RecordDecl
>(Parent
)) {
286 if (RD
->isAnonymousStructOrUnion())
288 } else if (auto ND
= dyn_cast
<NamedDecl
>(Parent
)) {
289 if (shouldSkipNamelessDecl(ND
))
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()) {
301 assert(D
->isCanonicalDecl());
308 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
309 bool IsRef
, SymbolRoleSet Roles
, ArrayRef
<SymbolRelation
> Relations
) {
313 auto acceptForRelation
= [](SymbolRoleSet roles
) -> bool {
315 applyForEachSymbolRoleInterruptible(roles
, [&accept
](SymbolRole r
) -> bool {
317 case SymbolRole::RelationChildOf
:
318 case SymbolRole::RelationBaseOf
:
319 case SymbolRole::RelationOverrideOf
:
320 case SymbolRole::RelationExtendedBy
:
321 case SymbolRole::RelationAccessorOf
:
322 case SymbolRole::RelationIBTypeOf
:
325 case SymbolRole::Declaration
:
326 case SymbolRole::Definition
:
327 case SymbolRole::Reference
:
328 case SymbolRole::Read
:
329 case SymbolRole::Write
:
330 case SymbolRole::Call
:
331 case SymbolRole::Dynamic
:
332 case SymbolRole::AddressOf
:
333 case SymbolRole::Implicit
:
334 case SymbolRole::Undefinition
:
335 case SymbolRole::RelationReceivedBy
:
336 case SymbolRole::RelationCalledBy
:
337 case SymbolRole::RelationContainedBy
:
338 case SymbolRole::RelationSpecializationOf
:
339 case SymbolRole::NameReference
:
342 llvm_unreachable("Unsupported SymbolRole value!");
347 for (auto &Rel
: Relations
) {
348 if (acceptForRelation(Rel
.Roles
))
355 bool IndexingContext::handleDeclOccurrence(const Decl
*D
, SourceLocation Loc
,
356 bool IsRef
, const Decl
*Parent
,
358 ArrayRef
<SymbolRelation
> Relations
,
361 const DeclContext
*ContainerDC
) {
362 if (D
->isImplicit() && !isa
<ObjCMethodDecl
>(D
))
364 if (!isa
<NamedDecl
>(D
) || shouldSkipNamelessDecl(cast
<NamedDecl
>(D
)))
367 SourceManager
&SM
= Ctx
->getSourceManager();
368 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
372 bool Invalid
= false;
373 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
374 if (Invalid
|| !SEntry
.isFile())
377 if (SEntry
.getFile().getFileCharacteristic() != SrcMgr::C_User
) {
378 switch (IndexOpts
.SystemSymbolFilter
) {
379 case IndexingOptions::SystemSymbolFilterKind::None
:
381 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
382 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef
, Roles
, Relations
))
385 case IndexingOptions::SystemSymbolFilterKind::All
:
393 if (isTemplateImplicitInstantiation(D
)) {
396 D
= adjustTemplateImplicitInstantiation(D
);
399 assert(!isTemplateImplicitInstantiation(D
));
403 Roles
|= (unsigned)SymbolRole::Reference
;
404 else if (isDeclADefinition(OrigD
, ContainerDC
, *Ctx
))
405 Roles
|= (unsigned)SymbolRole::Definition
;
407 Roles
|= (unsigned)SymbolRole::Declaration
;
409 D
= getCanonicalDecl(D
);
410 Parent
= adjustParent(Parent
);
412 Parent
= getCanonicalDecl(Parent
);
414 SmallVector
<SymbolRelation
, 6> FinalRelations
;
415 FinalRelations
.reserve(Relations
.size()+1);
417 auto addRelation
= [&](SymbolRelation Rel
) {
418 auto It
= llvm::find_if(FinalRelations
, [&](SymbolRelation Elem
) -> bool {
419 return Elem
.RelatedSymbol
== Rel
.RelatedSymbol
;
421 if (It
!= FinalRelations
.end()) {
422 It
->Roles
|= Rel
.Roles
;
424 FinalRelations
.push_back(Rel
);
430 if (IsRef
|| (!isa
<ParmVarDecl
>(D
) && isFunctionLocalSymbol(D
))) {
431 addRelation(SymbolRelation
{
432 (unsigned)SymbolRole::RelationContainedBy
,
436 addRelation(SymbolRelation
{
437 (unsigned)SymbolRole::RelationChildOf
,
443 for (auto &Rel
: Relations
) {
444 addRelation(SymbolRelation(Rel
.Roles
,
445 Rel
.RelatedSymbol
->getCanonicalDecl()));
448 IndexDataConsumer::ASTNodeInfo Node
{OrigE
, OrigD
, Parent
, ContainerDC
};
449 return DataConsumer
.handleDeclOccurrence(D
, Roles
, FinalRelations
, Loc
, Node
);
452 void IndexingContext::handleMacroDefined(const IdentifierInfo
&Name
,
454 const MacroInfo
&MI
) {
455 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc
))
457 SymbolRoleSet Roles
= (unsigned)SymbolRole::Definition
;
458 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
461 void IndexingContext::handleMacroUndefined(const IdentifierInfo
&Name
,
463 const MacroInfo
&MI
) {
464 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc
))
466 SymbolRoleSet Roles
= (unsigned)SymbolRole::Undefinition
;
467 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
470 void IndexingContext::handleMacroReference(const IdentifierInfo
&Name
,
472 const MacroInfo
&MI
) {
473 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc
))
475 SymbolRoleSet Roles
= (unsigned)SymbolRole::Reference
;
476 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
479 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef
,
480 SourceLocation Loc
) {
481 if (!IndexOpts
.IndexMacros
)
484 switch (IndexOpts
.SystemSymbolFilter
) {
485 case IndexingOptions::SystemSymbolFilterKind::None
:
487 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
491 case IndexingOptions::SystemSymbolFilterKind::All
:
495 SourceManager
&SM
= Ctx
->getSourceManager();
496 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
500 bool Invalid
= false;
501 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
502 if (Invalid
|| !SEntry
.isFile())
505 return SEntry
.getFile().getFileCharacteristic() == SrcMgr::C_User
;