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/Basic/SourceLocation.h"
11 #include "clang/Index/IndexDataConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/AST/DeclObjC.h"
15 #include "clang/Basic/SourceManager.h"
17 using namespace clang;
18 using namespace index;
20 static bool isGeneratedDecl(const Decl *D) {
21 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
22 return attr->getGeneratedDeclaration();
27 bool IndexingContext::shouldIndex(const Decl *D) {
28 return !isGeneratedDecl(D);
31 const LangOptions &IndexingContext::getLangOpts() const {
32 return Ctx->getLangOpts();
35 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
36 return IndexOpts.IndexFunctionLocals;
39 bool IndexingContext::shouldIndexImplicitInstantiation() const {
40 return IndexOpts.IndexImplicitInstantiation;
43 bool IndexingContext::shouldIndexParametersInDeclarations() const {
44 return IndexOpts.IndexParametersInDeclarations;
47 bool IndexingContext::shouldIndexTemplateParameters() const {
48 return IndexOpts.IndexTemplateParameters;
51 bool IndexingContext::handleDecl(const Decl *D,
53 ArrayRef<SymbolRelation> Relations) {
54 return handleDecl(D, D->getLocation(), Roles, Relations);
57 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
59 ArrayRef<SymbolRelation> Relations,
60 const DeclContext *DC) {
62 DC = D->getDeclContext();
64 const Decl *OrigD = D;
65 if (isa<ObjCPropertyImplDecl>(D)) {
66 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
68 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
73 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
74 const NamedDecl *Parent,
75 const DeclContext *DC,
77 ArrayRef<SymbolRelation> Relations,
80 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
83 if (!shouldIndexTemplateParameters() &&
84 (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
85 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.handleModuleOccurence(ImportD, Mod,
102 (SymbolRoleSet)SymbolRole::Reference,
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.handleModuleOccurence(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 case TSK_ExplicitSpecialization:
174 case TSK_ImplicitInstantiation:
175 case TSK_ExplicitInstantiationDeclaration:
176 case TSK_ExplicitInstantiationDefinition:
179 llvm_unreachable("invalid TemplateSpecializationKind");
182 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
183 if (isa<ObjCInterfaceDecl>(D))
185 if (isa<ObjCCategoryDecl>(D))
187 if (isa<ObjCIvarDecl>(D))
189 if (isa<ObjCMethodDecl>(D))
191 if (isa<ImportDecl>(D))
196 static const CXXRecordDecl *
197 getDeclContextForTemplateInstationPattern(const Decl *D) {
198 if (const auto *CTSD =
199 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
200 return CTSD->getTemplateInstantiationPattern();
201 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
202 return RD->getInstantiatedFromMemberClass();
206 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
207 if (const ClassTemplateSpecializationDecl *
208 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
209 return SD->getTemplateInstantiationPattern();
210 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
211 return FD->getTemplateInstantiationPattern();
212 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
213 return VD->getTemplateInstantiationPattern();
214 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
215 return RD->getInstantiatedFromMemberClass();
216 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
217 return ED->getInstantiatedFromMemberEnum();
218 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
219 const auto *ND = cast<NamedDecl>(D);
220 if (const CXXRecordDecl *Pattern =
221 getDeclContextForTemplateInstationPattern(ND)) {
222 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
223 if (BaseND->isImplicit())
225 if (BaseND->getKind() == ND->getKind())
229 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
230 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
231 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
232 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
240 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
241 if (auto VD = dyn_cast<VarDecl>(D))
242 return VD->isThisDeclarationADefinition(Ctx);
244 if (auto FD = dyn_cast<FunctionDecl>(D))
245 return FD->isThisDeclarationADefinition();
247 if (auto TD = dyn_cast<TagDecl>(D))
248 return TD->isThisDeclarationADefinition();
250 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
251 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
253 if (isa<TypedefNameDecl>(D) ||
254 isa<EnumConstantDecl>(D) ||
256 isa<MSPropertyDecl>(D) ||
257 isa<ObjCImplDecl>(D) ||
258 isa<ObjCPropertyImplDecl>(D))
264 /// Whether the given NamedDecl should be skipped because it has no name.
265 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
266 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
267 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
270 static const Decl *adjustParent(const Decl *Parent) {
273 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
274 if (isa<TranslationUnitDecl>(Parent))
276 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
278 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
279 if (NS->isAnonymousNamespace())
281 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
282 if (RD->isAnonymousStructOrUnion())
284 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
285 if (shouldSkipNamelessDecl(ND))
292 static const Decl *getCanonicalDecl(const Decl *D) {
293 D = D->getCanonicalDecl();
294 if (auto TD = dyn_cast<TemplateDecl>(D)) {
295 if (auto TTD = TD->getTemplatedDecl()) {
297 assert(D->isCanonicalDecl());
304 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
305 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
309 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
311 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
313 case SymbolRole::RelationChildOf:
314 case SymbolRole::RelationBaseOf:
315 case SymbolRole::RelationOverrideOf:
316 case SymbolRole::RelationExtendedBy:
317 case SymbolRole::RelationAccessorOf:
318 case SymbolRole::RelationIBTypeOf:
321 case SymbolRole::Declaration:
322 case SymbolRole::Definition:
323 case SymbolRole::Reference:
324 case SymbolRole::Read:
325 case SymbolRole::Write:
326 case SymbolRole::Call:
327 case SymbolRole::Dynamic:
328 case SymbolRole::AddressOf:
329 case SymbolRole::Implicit:
330 case SymbolRole::Undefinition:
331 case SymbolRole::RelationReceivedBy:
332 case SymbolRole::RelationCalledBy:
333 case SymbolRole::RelationContainedBy:
334 case SymbolRole::RelationSpecializationOf:
335 case SymbolRole::NameReference:
338 llvm_unreachable("Unsupported SymbolRole value!");
343 for (auto &Rel : Relations) {
344 if (acceptForRelation(Rel.Roles))
351 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
352 bool IsRef, const Decl *Parent,
354 ArrayRef<SymbolRelation> Relations,
357 const DeclContext *ContainerDC) {
358 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
360 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
363 SourceManager &SM = Ctx->getSourceManager();
364 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
368 bool Invalid = false;
369 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
370 if (Invalid || !SEntry.isFile())
373 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
374 switch (IndexOpts.SystemSymbolFilter) {
375 case IndexingOptions::SystemSymbolFilterKind::None:
377 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
378 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
381 case IndexingOptions::SystemSymbolFilterKind::All:
389 if (isTemplateImplicitInstantiation(D)) {
392 D = adjustTemplateImplicitInstantiation(D);
395 assert(!isTemplateImplicitInstantiation(D));
399 Roles |= (unsigned)SymbolRole::Reference;
400 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
401 Roles |= (unsigned)SymbolRole::Definition;
403 Roles |= (unsigned)SymbolRole::Declaration;
405 D = getCanonicalDecl(D);
406 Parent = adjustParent(Parent);
408 Parent = getCanonicalDecl(Parent);
410 SmallVector<SymbolRelation, 6> FinalRelations;
411 FinalRelations.reserve(Relations.size()+1);
413 auto addRelation = [&](SymbolRelation Rel) {
414 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
415 return Elem.RelatedSymbol == Rel.RelatedSymbol;
417 if (It != FinalRelations.end()) {
418 It->Roles |= Rel.Roles;
420 FinalRelations.push_back(Rel);
426 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
427 addRelation(SymbolRelation{
428 (unsigned)SymbolRole::RelationContainedBy,
432 addRelation(SymbolRelation{
433 (unsigned)SymbolRole::RelationChildOf,
439 for (auto &Rel : Relations) {
440 addRelation(SymbolRelation(Rel.Roles,
441 Rel.RelatedSymbol->getCanonicalDecl()));
444 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
445 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
448 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
450 const MacroInfo &MI) {
451 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
452 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
455 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
457 const MacroInfo &MI) {
458 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
459 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
462 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
464 const MacroInfo &MI) {
465 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
466 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);