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
,
81 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D
))
84 if (!shouldIndexTemplateParameters() &&
85 (isa
<NonTypeTemplateParmDecl
>(D
) || isa
<TemplateTypeParmDecl
>(D
) ||
86 isa
<TemplateTemplateParmDecl
>(D
))) {
89 return handleDeclOccurrence(D
, Loc
, /*IsRef=*/true, Parent
, Roles
, Relations
,
93 static void reportModuleReferences(const Module
*Mod
,
94 ArrayRef
<SourceLocation
> IdLocs
,
95 const ImportDecl
*ImportD
,
96 IndexDataConsumer
&DataConsumer
) {
99 reportModuleReferences(Mod
->Parent
, IdLocs
.drop_back(), ImportD
,
101 DataConsumer
.handleModuleOccurrence(
102 ImportD
, Mod
, (SymbolRoleSet
)SymbolRole::Reference
, IdLocs
.back());
105 bool IndexingContext::importedModule(const ImportDecl
*ImportD
) {
106 if (ImportD
->isInvalidDecl())
110 auto IdLocs
= ImportD
->getIdentifierLocs();
114 Loc
= ImportD
->getLocation();
116 SourceManager
&SM
= Ctx
->getSourceManager();
117 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
121 bool Invalid
= false;
122 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
123 if (Invalid
|| !SEntry
.isFile())
126 if (SEntry
.getFile().getFileCharacteristic() != SrcMgr::C_User
) {
127 switch (IndexOpts
.SystemSymbolFilter
) {
128 case IndexingOptions::SystemSymbolFilterKind::None
:
130 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
131 case IndexingOptions::SystemSymbolFilterKind::All
:
136 const Module
*Mod
= ImportD
->getImportedModule();
137 if (!ImportD
->isImplicit() && Mod
->Parent
&& !IdLocs
.empty()) {
138 reportModuleReferences(Mod
->Parent
, IdLocs
.drop_back(), ImportD
,
142 SymbolRoleSet Roles
= (unsigned)SymbolRole::Declaration
;
143 if (ImportD
->isImplicit())
144 Roles
|= (unsigned)SymbolRole::Implicit
;
146 return DataConsumer
.handleModuleOccurrence(ImportD
, Mod
, Roles
, Loc
);
149 bool IndexingContext::isTemplateImplicitInstantiation(const Decl
*D
) {
150 TemplateSpecializationKind TKind
= TSK_Undeclared
;
151 if (const ClassTemplateSpecializationDecl
*
152 SD
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
)) {
153 TKind
= SD
->getSpecializationKind();
154 } else if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
155 TKind
= FD
->getTemplateSpecializationKind();
156 } else if (auto *VD
= dyn_cast
<VarDecl
>(D
)) {
157 TKind
= VD
->getTemplateSpecializationKind();
158 } else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(D
)) {
159 if (RD
->getInstantiatedFromMemberClass())
160 TKind
= RD
->getTemplateSpecializationKind();
161 } else if (const auto *ED
= dyn_cast
<EnumDecl
>(D
)) {
162 if (ED
->getInstantiatedFromMemberEnum())
163 TKind
= ED
->getTemplateSpecializationKind();
164 } else if (isa
<FieldDecl
>(D
) || isa
<TypedefNameDecl
>(D
) ||
165 isa
<EnumConstantDecl
>(D
)) {
166 if (const auto *Parent
= dyn_cast
<Decl
>(D
->getDeclContext()))
167 return isTemplateImplicitInstantiation(Parent
);
171 // Instantiation maybe not happen yet when we see a SpecializationDecl,
172 // e.g. when the type doesn't need to be complete, we still treat it as an
173 // instantiation as we'd like to keep the canonicalized result consistent.
174 return isa
<ClassTemplateSpecializationDecl
>(D
);
175 case TSK_ExplicitSpecialization
:
177 case TSK_ImplicitInstantiation
:
178 case TSK_ExplicitInstantiationDeclaration
:
179 case TSK_ExplicitInstantiationDefinition
:
182 llvm_unreachable("invalid TemplateSpecializationKind");
185 bool IndexingContext::shouldIgnoreIfImplicit(const Decl
*D
) {
186 if (isa
<ObjCInterfaceDecl
>(D
))
188 if (isa
<ObjCCategoryDecl
>(D
))
190 if (isa
<ObjCIvarDecl
>(D
))
192 if (isa
<ObjCMethodDecl
>(D
))
194 if (isa
<ImportDecl
>(D
))
199 static const CXXRecordDecl
*
200 getDeclContextForTemplateInstationPattern(const Decl
*D
) {
201 if (const auto *CTSD
=
202 dyn_cast
<ClassTemplateSpecializationDecl
>(D
->getDeclContext()))
203 return CTSD
->getTemplateInstantiationPattern();
204 else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(D
->getDeclContext()))
205 return RD
->getInstantiatedFromMemberClass();
209 static const Decl
*adjustTemplateImplicitInstantiation(const Decl
*D
) {
210 if (const ClassTemplateSpecializationDecl
*
211 SD
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
)) {
212 const auto *Template
= SD
->getTemplateInstantiationPattern();
215 // Fallback to primary template if no instantiation is available yet (e.g.
216 // the type doesn't need to be complete).
217 return SD
->getSpecializedTemplate()->getTemplatedDecl();
218 } else if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
219 return FD
->getTemplateInstantiationPattern();
220 } else if (auto *VD
= dyn_cast
<VarDecl
>(D
)) {
221 return VD
->getTemplateInstantiationPattern();
222 } else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(D
)) {
223 return RD
->getInstantiatedFromMemberClass();
224 } else if (const auto *ED
= dyn_cast
<EnumDecl
>(D
)) {
225 return ED
->getInstantiatedFromMemberEnum();
226 } else if (isa
<FieldDecl
>(D
) || isa
<TypedefNameDecl
>(D
)) {
227 const auto *ND
= cast
<NamedDecl
>(D
);
228 if (const CXXRecordDecl
*Pattern
=
229 getDeclContextForTemplateInstationPattern(ND
)) {
230 for (const NamedDecl
*BaseND
: Pattern
->lookup(ND
->getDeclName())) {
231 if (BaseND
->isImplicit())
233 if (BaseND
->getKind() == ND
->getKind())
237 } else if (const auto *ECD
= dyn_cast
<EnumConstantDecl
>(D
)) {
238 if (const auto *ED
= dyn_cast
<EnumDecl
>(ECD
->getDeclContext())) {
239 if (const EnumDecl
*Pattern
= ED
->getInstantiatedFromMemberEnum()) {
240 for (const NamedDecl
*BaseECD
: Pattern
->lookup(ECD
->getDeclName()))
248 static bool isDeclADefinition(const Decl
*D
, const DeclContext
*ContainerDC
, ASTContext
&Ctx
) {
249 if (auto VD
= dyn_cast
<VarDecl
>(D
))
250 return VD
->isThisDeclarationADefinition(Ctx
);
252 if (auto FD
= dyn_cast
<FunctionDecl
>(D
))
253 return FD
->isThisDeclarationADefinition();
255 if (auto TD
= dyn_cast
<TagDecl
>(D
))
256 return TD
->isThisDeclarationADefinition();
258 if (auto MD
= dyn_cast
<ObjCMethodDecl
>(D
))
259 return MD
->isThisDeclarationADefinition() || isa
<ObjCImplDecl
>(ContainerDC
);
261 if (isa
<TypedefNameDecl
>(D
) || isa
<EnumConstantDecl
>(D
) ||
262 isa
<FieldDecl
>(D
) || isa
<MSPropertyDecl
>(D
) || isa
<ObjCImplDecl
>(D
) ||
263 isa
<ObjCPropertyImplDecl
>(D
) || isa
<ConceptDecl
>(D
))
269 /// Whether the given NamedDecl should be skipped because it has no name.
270 static bool shouldSkipNamelessDecl(const NamedDecl
*ND
) {
271 return (ND
->getDeclName().isEmpty() && !isa
<TagDecl
>(ND
) &&
272 !isa
<ObjCCategoryDecl
>(ND
)) || isa
<CXXDeductionGuideDecl
>(ND
);
275 static const Decl
*adjustParent(const Decl
*Parent
) {
278 for (;; Parent
= cast
<Decl
>(Parent
->getDeclContext())) {
279 if (isa
<TranslationUnitDecl
>(Parent
))
281 if (isa
<LinkageSpecDecl
>(Parent
) || isa
<BlockDecl
>(Parent
))
283 if (auto NS
= dyn_cast
<NamespaceDecl
>(Parent
)) {
284 if (NS
->isAnonymousNamespace())
286 } else if (auto RD
= dyn_cast
<RecordDecl
>(Parent
)) {
287 if (RD
->isAnonymousStructOrUnion())
289 } else if (auto ND
= dyn_cast
<NamedDecl
>(Parent
)) {
290 if (shouldSkipNamelessDecl(ND
))
297 static const Decl
*getCanonicalDecl(const Decl
*D
) {
298 D
= D
->getCanonicalDecl();
299 if (auto TD
= dyn_cast
<TemplateDecl
>(D
)) {
300 if (auto TTD
= TD
->getTemplatedDecl()) {
302 assert(D
->isCanonicalDecl());
309 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
310 bool IsRef
, SymbolRoleSet Roles
, ArrayRef
<SymbolRelation
> Relations
) {
314 auto acceptForRelation
= [](SymbolRoleSet roles
) -> bool {
316 applyForEachSymbolRoleInterruptible(roles
, [&accept
](SymbolRole r
) -> bool {
318 case SymbolRole::RelationChildOf
:
319 case SymbolRole::RelationBaseOf
:
320 case SymbolRole::RelationOverrideOf
:
321 case SymbolRole::RelationExtendedBy
:
322 case SymbolRole::RelationAccessorOf
:
323 case SymbolRole::RelationIBTypeOf
:
326 case SymbolRole::Declaration
:
327 case SymbolRole::Definition
:
328 case SymbolRole::Reference
:
329 case SymbolRole::Read
:
330 case SymbolRole::Write
:
331 case SymbolRole::Call
:
332 case SymbolRole::Dynamic
:
333 case SymbolRole::AddressOf
:
334 case SymbolRole::Implicit
:
335 case SymbolRole::Undefinition
:
336 case SymbolRole::RelationReceivedBy
:
337 case SymbolRole::RelationCalledBy
:
338 case SymbolRole::RelationContainedBy
:
339 case SymbolRole::RelationSpecializationOf
:
340 case SymbolRole::NameReference
:
343 llvm_unreachable("Unsupported SymbolRole value!");
348 for (auto &Rel
: Relations
) {
349 if (acceptForRelation(Rel
.Roles
))
356 bool IndexingContext::handleDeclOccurrence(const Decl
*D
, SourceLocation Loc
,
357 bool IsRef
, const Decl
*Parent
,
359 ArrayRef
<SymbolRelation
> Relations
,
362 const DeclContext
*ContainerDC
) {
363 if (D
->isImplicit() && !isa
<ObjCMethodDecl
>(D
))
365 if (!isa
<NamedDecl
>(D
) || shouldSkipNamelessDecl(cast
<NamedDecl
>(D
)))
368 SourceManager
&SM
= Ctx
->getSourceManager();
369 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
373 bool Invalid
= false;
374 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
375 if (Invalid
|| !SEntry
.isFile())
378 if (SEntry
.getFile().getFileCharacteristic() != SrcMgr::C_User
) {
379 switch (IndexOpts
.SystemSymbolFilter
) {
380 case IndexingOptions::SystemSymbolFilterKind::None
:
382 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
383 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef
, Roles
, Relations
))
386 case IndexingOptions::SystemSymbolFilterKind::All
:
394 if (isTemplateImplicitInstantiation(D
)) {
397 D
= adjustTemplateImplicitInstantiation(D
);
400 assert(!isTemplateImplicitInstantiation(D
));
404 Roles
|= (unsigned)SymbolRole::Reference
;
405 else if (isDeclADefinition(OrigD
, ContainerDC
, *Ctx
))
406 Roles
|= (unsigned)SymbolRole::Definition
;
408 Roles
|= (unsigned)SymbolRole::Declaration
;
410 D
= getCanonicalDecl(D
);
411 Parent
= adjustParent(Parent
);
413 Parent
= getCanonicalDecl(Parent
);
415 SmallVector
<SymbolRelation
, 6> FinalRelations
;
416 FinalRelations
.reserve(Relations
.size()+1);
418 auto addRelation
= [&](SymbolRelation Rel
) {
419 auto It
= llvm::find_if(FinalRelations
, [&](SymbolRelation Elem
) -> bool {
420 return Elem
.RelatedSymbol
== Rel
.RelatedSymbol
;
422 if (It
!= FinalRelations
.end()) {
423 It
->Roles
|= Rel
.Roles
;
425 FinalRelations
.push_back(Rel
);
431 if (IsRef
|| (!isa
<ParmVarDecl
>(D
) && isFunctionLocalSymbol(D
))) {
432 addRelation(SymbolRelation
{
433 (unsigned)SymbolRole::RelationContainedBy
,
437 addRelation(SymbolRelation
{
438 (unsigned)SymbolRole::RelationChildOf
,
444 for (auto &Rel
: Relations
) {
445 addRelation(SymbolRelation(Rel
.Roles
,
446 Rel
.RelatedSymbol
->getCanonicalDecl()));
449 IndexDataConsumer::ASTNodeInfo Node
{OrigE
, OrigD
, Parent
, ContainerDC
};
450 return DataConsumer
.handleDeclOccurrence(D
, Roles
, FinalRelations
, Loc
, Node
);
453 void IndexingContext::handleMacroDefined(const IdentifierInfo
&Name
,
455 const MacroInfo
&MI
) {
456 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc
))
458 SymbolRoleSet Roles
= (unsigned)SymbolRole::Definition
;
459 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
462 void IndexingContext::handleMacroUndefined(const IdentifierInfo
&Name
,
464 const MacroInfo
&MI
) {
465 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc
))
467 SymbolRoleSet Roles
= (unsigned)SymbolRole::Undefinition
;
468 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
471 void IndexingContext::handleMacroReference(const IdentifierInfo
&Name
,
473 const MacroInfo
&MI
) {
474 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc
))
476 SymbolRoleSet Roles
= (unsigned)SymbolRole::Reference
;
477 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
480 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef
,
481 SourceLocation Loc
) {
482 if (!IndexOpts
.IndexMacros
)
485 switch (IndexOpts
.SystemSymbolFilter
) {
486 case IndexingOptions::SystemSymbolFilterKind::None
:
488 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
492 case IndexingOptions::SystemSymbolFilterKind::All
:
496 SourceManager
&SM
= Ctx
->getSourceManager();
497 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
501 bool Invalid
= false;
502 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
503 if (Invalid
|| !SEntry
.isFile())
506 return SEntry
.getFile().getFileCharacteristic() == SrcMgr::C_User
;