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
))) {
90 return handleDeclOccurrence(D
, Loc
, /*IsRef=*/true, Parent
, Roles
, Relations
,
94 static void reportModuleReferences(const Module
*Mod
,
95 ArrayRef
<SourceLocation
> IdLocs
,
96 const ImportDecl
*ImportD
,
97 IndexDataConsumer
&DataConsumer
) {
100 reportModuleReferences(Mod
->Parent
, IdLocs
.drop_back(), ImportD
,
102 DataConsumer
.handleModuleOccurrence(
103 ImportD
, Mod
, (SymbolRoleSet
)SymbolRole::Reference
, IdLocs
.back());
106 bool IndexingContext::importedModule(const ImportDecl
*ImportD
) {
107 if (ImportD
->isInvalidDecl())
111 auto IdLocs
= ImportD
->getIdentifierLocs();
115 Loc
= ImportD
->getLocation();
117 SourceManager
&SM
= Ctx
->getSourceManager();
118 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
122 bool Invalid
= false;
123 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
124 if (Invalid
|| !SEntry
.isFile())
127 if (SEntry
.getFile().getFileCharacteristic() != SrcMgr::C_User
) {
128 switch (IndexOpts
.SystemSymbolFilter
) {
129 case IndexingOptions::SystemSymbolFilterKind::None
:
131 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
132 case IndexingOptions::SystemSymbolFilterKind::All
:
137 const Module
*Mod
= ImportD
->getImportedModule();
138 if (!ImportD
->isImplicit() && Mod
->Parent
&& !IdLocs
.empty()) {
139 reportModuleReferences(Mod
->Parent
, IdLocs
.drop_back(), ImportD
,
143 SymbolRoleSet Roles
= (unsigned)SymbolRole::Declaration
;
144 if (ImportD
->isImplicit())
145 Roles
|= (unsigned)SymbolRole::Implicit
;
147 return DataConsumer
.handleModuleOccurrence(ImportD
, Mod
, Roles
, Loc
);
150 bool IndexingContext::isTemplateImplicitInstantiation(const Decl
*D
) {
151 TemplateSpecializationKind TKind
= TSK_Undeclared
;
152 if (const ClassTemplateSpecializationDecl
*
153 SD
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
)) {
154 TKind
= SD
->getSpecializationKind();
155 } else if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
156 TKind
= FD
->getTemplateSpecializationKind();
157 } else if (auto *VD
= dyn_cast
<VarDecl
>(D
)) {
158 TKind
= VD
->getTemplateSpecializationKind();
159 } else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(D
)) {
160 if (RD
->getInstantiatedFromMemberClass())
161 TKind
= RD
->getTemplateSpecializationKind();
162 } else if (const auto *ED
= dyn_cast
<EnumDecl
>(D
)) {
163 if (ED
->getInstantiatedFromMemberEnum())
164 TKind
= ED
->getTemplateSpecializationKind();
165 } else if (isa
<FieldDecl
>(D
) || isa
<TypedefNameDecl
>(D
) ||
166 isa
<EnumConstantDecl
>(D
)) {
167 if (const auto *Parent
= dyn_cast
<Decl
>(D
->getDeclContext()))
168 return isTemplateImplicitInstantiation(Parent
);
172 // Instantiation maybe not happen yet when we see a SpecializationDecl,
173 // e.g. when the type doesn't need to be complete, we still treat it as an
174 // instantiation as we'd like to keep the canonicalized result consistent.
175 return isa
<ClassTemplateSpecializationDecl
>(D
);
176 case TSK_ExplicitSpecialization
:
178 case TSK_ImplicitInstantiation
:
179 case TSK_ExplicitInstantiationDeclaration
:
180 case TSK_ExplicitInstantiationDefinition
:
183 llvm_unreachable("invalid TemplateSpecializationKind");
186 bool IndexingContext::shouldIgnoreIfImplicit(const Decl
*D
) {
187 if (isa
<ObjCInterfaceDecl
>(D
))
189 if (isa
<ObjCCategoryDecl
>(D
))
191 if (isa
<ObjCIvarDecl
>(D
))
193 if (isa
<ObjCMethodDecl
>(D
))
195 if (isa
<ImportDecl
>(D
))
200 static const CXXRecordDecl
*
201 getDeclContextForTemplateInstationPattern(const Decl
*D
) {
202 if (const auto *CTSD
=
203 dyn_cast
<ClassTemplateSpecializationDecl
>(D
->getDeclContext()))
204 return CTSD
->getTemplateInstantiationPattern();
205 else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(D
->getDeclContext()))
206 return RD
->getInstantiatedFromMemberClass();
210 static const Decl
*adjustTemplateImplicitInstantiation(const Decl
*D
) {
211 if (const ClassTemplateSpecializationDecl
*
212 SD
= dyn_cast
<ClassTemplateSpecializationDecl
>(D
)) {
213 const auto *Template
= SD
->getTemplateInstantiationPattern();
216 // Fallback to primary template if no instantiation is available yet (e.g.
217 // the type doesn't need to be complete).
218 return SD
->getSpecializedTemplate()->getTemplatedDecl();
219 } else if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
220 return FD
->getTemplateInstantiationPattern();
221 } else if (auto *VD
= dyn_cast
<VarDecl
>(D
)) {
222 return VD
->getTemplateInstantiationPattern();
223 } else if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(D
)) {
224 return RD
->getInstantiatedFromMemberClass();
225 } else if (const auto *ED
= dyn_cast
<EnumDecl
>(D
)) {
226 return ED
->getInstantiatedFromMemberEnum();
227 } else if (isa
<FieldDecl
>(D
) || isa
<TypedefNameDecl
>(D
)) {
228 const auto *ND
= cast
<NamedDecl
>(D
);
229 if (const CXXRecordDecl
*Pattern
=
230 getDeclContextForTemplateInstationPattern(ND
)) {
231 for (const NamedDecl
*BaseND
: Pattern
->lookup(ND
->getDeclName())) {
232 if (BaseND
->isImplicit())
234 if (BaseND
->getKind() == ND
->getKind())
238 } else if (const auto *ECD
= dyn_cast
<EnumConstantDecl
>(D
)) {
239 if (const auto *ED
= dyn_cast
<EnumDecl
>(ECD
->getDeclContext())) {
240 if (const EnumDecl
*Pattern
= ED
->getInstantiatedFromMemberEnum()) {
241 for (const NamedDecl
*BaseECD
: Pattern
->lookup(ECD
->getDeclName()))
249 static bool isDeclADefinition(const Decl
*D
, const DeclContext
*ContainerDC
, ASTContext
&Ctx
) {
250 if (auto VD
= dyn_cast
<VarDecl
>(D
))
251 return VD
->isThisDeclarationADefinition(Ctx
);
253 if (auto FD
= dyn_cast
<FunctionDecl
>(D
))
254 return FD
->isThisDeclarationADefinition();
256 if (auto TD
= dyn_cast
<TagDecl
>(D
))
257 return TD
->isThisDeclarationADefinition();
259 if (auto MD
= dyn_cast
<ObjCMethodDecl
>(D
))
260 return MD
->isThisDeclarationADefinition() || isa
<ObjCImplDecl
>(ContainerDC
);
262 if (isa
<TypedefNameDecl
>(D
) ||
263 isa
<EnumConstantDecl
>(D
) ||
265 isa
<MSPropertyDecl
>(D
) ||
266 isa
<ObjCImplDecl
>(D
) ||
267 isa
<ObjCPropertyImplDecl
>(D
))
273 /// Whether the given NamedDecl should be skipped because it has no name.
274 static bool shouldSkipNamelessDecl(const NamedDecl
*ND
) {
275 return (ND
->getDeclName().isEmpty() && !isa
<TagDecl
>(ND
) &&
276 !isa
<ObjCCategoryDecl
>(ND
)) || isa
<CXXDeductionGuideDecl
>(ND
);
279 static const Decl
*adjustParent(const Decl
*Parent
) {
282 for (;; Parent
= cast
<Decl
>(Parent
->getDeclContext())) {
283 if (isa
<TranslationUnitDecl
>(Parent
))
285 if (isa
<LinkageSpecDecl
>(Parent
) || isa
<BlockDecl
>(Parent
))
287 if (auto NS
= dyn_cast
<NamespaceDecl
>(Parent
)) {
288 if (NS
->isAnonymousNamespace())
290 } else if (auto RD
= dyn_cast
<RecordDecl
>(Parent
)) {
291 if (RD
->isAnonymousStructOrUnion())
293 } else if (auto ND
= dyn_cast
<NamedDecl
>(Parent
)) {
294 if (shouldSkipNamelessDecl(ND
))
301 static const Decl
*getCanonicalDecl(const Decl
*D
) {
302 D
= D
->getCanonicalDecl();
303 if (auto TD
= dyn_cast
<TemplateDecl
>(D
)) {
304 if (auto TTD
= TD
->getTemplatedDecl()) {
306 assert(D
->isCanonicalDecl());
313 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
314 bool IsRef
, SymbolRoleSet Roles
, ArrayRef
<SymbolRelation
> Relations
) {
318 auto acceptForRelation
= [](SymbolRoleSet roles
) -> bool {
320 applyForEachSymbolRoleInterruptible(roles
, [&accept
](SymbolRole r
) -> bool {
322 case SymbolRole::RelationChildOf
:
323 case SymbolRole::RelationBaseOf
:
324 case SymbolRole::RelationOverrideOf
:
325 case SymbolRole::RelationExtendedBy
:
326 case SymbolRole::RelationAccessorOf
:
327 case SymbolRole::RelationIBTypeOf
:
330 case SymbolRole::Declaration
:
331 case SymbolRole::Definition
:
332 case SymbolRole::Reference
:
333 case SymbolRole::Read
:
334 case SymbolRole::Write
:
335 case SymbolRole::Call
:
336 case SymbolRole::Dynamic
:
337 case SymbolRole::AddressOf
:
338 case SymbolRole::Implicit
:
339 case SymbolRole::Undefinition
:
340 case SymbolRole::RelationReceivedBy
:
341 case SymbolRole::RelationCalledBy
:
342 case SymbolRole::RelationContainedBy
:
343 case SymbolRole::RelationSpecializationOf
:
344 case SymbolRole::NameReference
:
347 llvm_unreachable("Unsupported SymbolRole value!");
352 for (auto &Rel
: Relations
) {
353 if (acceptForRelation(Rel
.Roles
))
360 bool IndexingContext::handleDeclOccurrence(const Decl
*D
, SourceLocation Loc
,
361 bool IsRef
, const Decl
*Parent
,
363 ArrayRef
<SymbolRelation
> Relations
,
366 const DeclContext
*ContainerDC
) {
367 if (D
->isImplicit() && !isa
<ObjCMethodDecl
>(D
))
369 if (!isa
<NamedDecl
>(D
) || shouldSkipNamelessDecl(cast
<NamedDecl
>(D
)))
372 SourceManager
&SM
= Ctx
->getSourceManager();
373 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
377 bool Invalid
= false;
378 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
379 if (Invalid
|| !SEntry
.isFile())
382 if (SEntry
.getFile().getFileCharacteristic() != SrcMgr::C_User
) {
383 switch (IndexOpts
.SystemSymbolFilter
) {
384 case IndexingOptions::SystemSymbolFilterKind::None
:
386 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
387 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef
, Roles
, Relations
))
390 case IndexingOptions::SystemSymbolFilterKind::All
:
398 if (isTemplateImplicitInstantiation(D
)) {
401 D
= adjustTemplateImplicitInstantiation(D
);
404 assert(!isTemplateImplicitInstantiation(D
));
408 Roles
|= (unsigned)SymbolRole::Reference
;
409 else if (isDeclADefinition(OrigD
, ContainerDC
, *Ctx
))
410 Roles
|= (unsigned)SymbolRole::Definition
;
412 Roles
|= (unsigned)SymbolRole::Declaration
;
414 D
= getCanonicalDecl(D
);
415 Parent
= adjustParent(Parent
);
417 Parent
= getCanonicalDecl(Parent
);
419 SmallVector
<SymbolRelation
, 6> FinalRelations
;
420 FinalRelations
.reserve(Relations
.size()+1);
422 auto addRelation
= [&](SymbolRelation Rel
) {
423 auto It
= llvm::find_if(FinalRelations
, [&](SymbolRelation Elem
) -> bool {
424 return Elem
.RelatedSymbol
== Rel
.RelatedSymbol
;
426 if (It
!= FinalRelations
.end()) {
427 It
->Roles
|= Rel
.Roles
;
429 FinalRelations
.push_back(Rel
);
435 if (IsRef
|| (!isa
<ParmVarDecl
>(D
) && isFunctionLocalSymbol(D
))) {
436 addRelation(SymbolRelation
{
437 (unsigned)SymbolRole::RelationContainedBy
,
441 addRelation(SymbolRelation
{
442 (unsigned)SymbolRole::RelationChildOf
,
448 for (auto &Rel
: Relations
) {
449 addRelation(SymbolRelation(Rel
.Roles
,
450 Rel
.RelatedSymbol
->getCanonicalDecl()));
453 IndexDataConsumer::ASTNodeInfo Node
{OrigE
, OrigD
, Parent
, ContainerDC
};
454 return DataConsumer
.handleDeclOccurrence(D
, Roles
, FinalRelations
, Loc
, Node
);
457 void IndexingContext::handleMacroDefined(const IdentifierInfo
&Name
,
459 const MacroInfo
&MI
) {
460 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc
))
462 SymbolRoleSet Roles
= (unsigned)SymbolRole::Definition
;
463 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
466 void IndexingContext::handleMacroUndefined(const IdentifierInfo
&Name
,
468 const MacroInfo
&MI
) {
469 if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc
))
471 SymbolRoleSet Roles
= (unsigned)SymbolRole::Undefinition
;
472 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
475 void IndexingContext::handleMacroReference(const IdentifierInfo
&Name
,
477 const MacroInfo
&MI
) {
478 if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc
))
480 SymbolRoleSet Roles
= (unsigned)SymbolRole::Reference
;
481 DataConsumer
.handleMacroOccurrence(&Name
, &MI
, Roles
, Loc
);
484 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef
,
485 SourceLocation Loc
) {
486 if (!IndexOpts
.IndexMacros
)
489 switch (IndexOpts
.SystemSymbolFilter
) {
490 case IndexingOptions::SystemSymbolFilterKind::None
:
492 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly
:
496 case IndexingOptions::SystemSymbolFilterKind::All
:
500 SourceManager
&SM
= Ctx
->getSourceManager();
501 FileID FID
= SM
.getFileID(SM
.getFileLoc(Loc
));
505 bool Invalid
= false;
506 const SrcMgr::SLocEntry
&SEntry
= SM
.getSLocEntry(FID
, &Invalid
);
507 if (Invalid
|| !SEntry
.isFile())
510 return SEntry
.getFile().getFileCharacteristic() == SrcMgr::C_User
;