1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "IndexingContext.h"
11 #include "clang/Basic/SourceLocation.h"
12 #include "clang/Index/IndexDataConsumer.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/AST/DeclObjC.h"
16 #include "clang/Basic/SourceManager.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::handleDecl(const Decl *D,
46 ArrayRef<SymbolRelation> Relations) {
47 return handleDecl(D, D->getLocation(), Roles, Relations);
50 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
52 ArrayRef<SymbolRelation> Relations,
53 const DeclContext *DC) {
55 DC = D->getDeclContext();
57 const Decl *OrigD = D;
58 if (isa<ObjCPropertyImplDecl>(D)) {
59 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
61 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
66 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
67 const NamedDecl *Parent,
68 const DeclContext *DC,
70 ArrayRef<SymbolRelation> Relations,
73 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
76 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
79 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
83 static void reportModuleReferences(const Module *Mod,
84 ArrayRef<SourceLocation> IdLocs,
85 const ImportDecl *ImportD,
86 IndexDataConsumer &DataConsumer) {
89 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
91 DataConsumer.handleModuleOccurence(ImportD, Mod,
92 (SymbolRoleSet)SymbolRole::Reference,
96 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
97 if (ImportD->isInvalidDecl())
101 auto IdLocs = ImportD->getIdentifierLocs();
105 Loc = ImportD->getLocation();
107 SourceManager &SM = Ctx->getSourceManager();
108 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
112 bool Invalid = false;
113 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
114 if (Invalid || !SEntry.isFile())
117 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
118 switch (IndexOpts.SystemSymbolFilter) {
119 case IndexingOptions::SystemSymbolFilterKind::None:
121 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
122 case IndexingOptions::SystemSymbolFilterKind::All:
127 const Module *Mod = ImportD->getImportedModule();
128 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
129 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
133 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
134 if (ImportD->isImplicit())
135 Roles |= (unsigned)SymbolRole::Implicit;
137 return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc);
140 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
141 TemplateSpecializationKind TKind = TSK_Undeclared;
142 if (const ClassTemplateSpecializationDecl *
143 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
144 TKind = SD->getSpecializationKind();
145 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
146 TKind = FD->getTemplateSpecializationKind();
147 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
148 TKind = VD->getTemplateSpecializationKind();
149 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
150 if (RD->getInstantiatedFromMemberClass())
151 TKind = RD->getTemplateSpecializationKind();
152 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
153 if (ED->getInstantiatedFromMemberEnum())
154 TKind = ED->getTemplateSpecializationKind();
155 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
156 isa<EnumConstantDecl>(D)) {
157 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
158 return isTemplateImplicitInstantiation(Parent);
162 case TSK_ExplicitSpecialization:
164 case TSK_ImplicitInstantiation:
165 case TSK_ExplicitInstantiationDeclaration:
166 case TSK_ExplicitInstantiationDefinition:
169 llvm_unreachable("invalid TemplateSpecializationKind");
172 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
173 if (isa<ObjCInterfaceDecl>(D))
175 if (isa<ObjCCategoryDecl>(D))
177 if (isa<ObjCIvarDecl>(D))
179 if (isa<ObjCMethodDecl>(D))
181 if (isa<ImportDecl>(D))
186 static const CXXRecordDecl *
187 getDeclContextForTemplateInstationPattern(const Decl *D) {
188 if (const auto *CTSD =
189 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
190 return CTSD->getTemplateInstantiationPattern();
191 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
192 return RD->getInstantiatedFromMemberClass();
196 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
197 if (const ClassTemplateSpecializationDecl *
198 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
199 return SD->getTemplateInstantiationPattern();
200 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
201 return FD->getTemplateInstantiationPattern();
202 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
203 return VD->getTemplateInstantiationPattern();
204 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
205 return RD->getInstantiatedFromMemberClass();
206 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
207 return ED->getInstantiatedFromMemberEnum();
208 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
209 const auto *ND = cast<NamedDecl>(D);
210 if (const CXXRecordDecl *Pattern =
211 getDeclContextForTemplateInstationPattern(ND)) {
212 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
213 if (BaseND->isImplicit())
215 if (BaseND->getKind() == ND->getKind())
219 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
220 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
221 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
222 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
230 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
231 if (auto VD = dyn_cast<VarDecl>(D))
232 return VD->isThisDeclarationADefinition(Ctx);
234 if (auto FD = dyn_cast<FunctionDecl>(D))
235 return FD->isThisDeclarationADefinition();
237 if (auto TD = dyn_cast<TagDecl>(D))
238 return TD->isThisDeclarationADefinition();
240 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
241 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
243 if (isa<TypedefNameDecl>(D) ||
244 isa<EnumConstantDecl>(D) ||
246 isa<MSPropertyDecl>(D) ||
247 isa<ObjCImplDecl>(D) ||
248 isa<ObjCPropertyImplDecl>(D))
254 /// Whether the given NamedDecl should be skipped because it has no name.
255 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
256 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
257 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
260 static const Decl *adjustParent(const Decl *Parent) {
263 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
264 if (isa<TranslationUnitDecl>(Parent))
266 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
268 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
269 if (NS->isAnonymousNamespace())
271 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
272 if (RD->isAnonymousStructOrUnion())
274 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
275 if (shouldSkipNamelessDecl(ND))
282 static const Decl *getCanonicalDecl(const Decl *D) {
283 D = D->getCanonicalDecl();
284 if (auto TD = dyn_cast<TemplateDecl>(D)) {
285 if (auto TTD = TD->getTemplatedDecl()) {
287 assert(D->isCanonicalDecl());
294 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
295 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
299 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
301 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
303 case SymbolRole::RelationChildOf:
304 case SymbolRole::RelationBaseOf:
305 case SymbolRole::RelationOverrideOf:
306 case SymbolRole::RelationExtendedBy:
307 case SymbolRole::RelationAccessorOf:
308 case SymbolRole::RelationIBTypeOf:
311 case SymbolRole::Declaration:
312 case SymbolRole::Definition:
313 case SymbolRole::Reference:
314 case SymbolRole::Read:
315 case SymbolRole::Write:
316 case SymbolRole::Call:
317 case SymbolRole::Dynamic:
318 case SymbolRole::AddressOf:
319 case SymbolRole::Implicit:
320 case SymbolRole::Undefinition:
321 case SymbolRole::RelationReceivedBy:
322 case SymbolRole::RelationCalledBy:
323 case SymbolRole::RelationContainedBy:
324 case SymbolRole::RelationSpecializationOf:
327 llvm_unreachable("Unsupported SymbolRole value!");
332 for (auto &Rel : Relations) {
333 if (acceptForRelation(Rel.Roles))
340 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
341 bool IsRef, const Decl *Parent,
343 ArrayRef<SymbolRelation> Relations,
346 const DeclContext *ContainerDC) {
347 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
349 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
352 SourceManager &SM = Ctx->getSourceManager();
353 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
357 bool Invalid = false;
358 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
359 if (Invalid || !SEntry.isFile())
362 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
363 switch (IndexOpts.SystemSymbolFilter) {
364 case IndexingOptions::SystemSymbolFilterKind::None:
366 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
367 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
370 case IndexingOptions::SystemSymbolFilterKind::All:
378 if (isTemplateImplicitInstantiation(D)) {
381 D = adjustTemplateImplicitInstantiation(D);
384 assert(!isTemplateImplicitInstantiation(D));
388 Roles |= (unsigned)SymbolRole::Reference;
389 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
390 Roles |= (unsigned)SymbolRole::Definition;
392 Roles |= (unsigned)SymbolRole::Declaration;
394 D = getCanonicalDecl(D);
395 Parent = adjustParent(Parent);
397 Parent = getCanonicalDecl(Parent);
399 SmallVector<SymbolRelation, 6> FinalRelations;
400 FinalRelations.reserve(Relations.size()+1);
402 auto addRelation = [&](SymbolRelation Rel) {
403 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
404 [&](SymbolRelation Elem)->bool {
405 return Elem.RelatedSymbol == Rel.RelatedSymbol;
407 if (It != FinalRelations.end()) {
408 It->Roles |= Rel.Roles;
410 FinalRelations.push_back(Rel);
416 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
417 addRelation(SymbolRelation{
418 (unsigned)SymbolRole::RelationContainedBy,
422 addRelation(SymbolRelation{
423 (unsigned)SymbolRole::RelationChildOf,
429 for (auto &Rel : Relations) {
430 addRelation(SymbolRelation(Rel.Roles,
431 Rel.RelatedSymbol->getCanonicalDecl()));
434 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
435 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
438 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
440 const MacroInfo &MI) {
441 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
442 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
445 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
447 const MacroInfo &MI) {
448 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
449 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
452 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
454 const MacroInfo &MI) {
455 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
456 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);