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/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::handleDecl(const Decl *D,
41 ArrayRef<SymbolRelation> Relations) {
42 return handleDecl(D, D->getLocation(), Roles, Relations);
45 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
47 ArrayRef<SymbolRelation> Relations,
48 const DeclContext *DC) {
50 DC = D->getDeclContext();
52 const Decl *OrigD = D;
53 if (isa<ObjCPropertyImplDecl>(D)) {
54 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
56 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
61 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
62 const NamedDecl *Parent,
63 const DeclContext *DC,
65 ArrayRef<SymbolRelation> Relations,
68 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
71 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
74 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
78 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
80 auto IdLocs = ImportD->getIdentifierLocs();
84 Loc = ImportD->getLocation();
85 SourceManager &SM = Ctx->getSourceManager();
86 Loc = SM.getFileLoc(Loc);
92 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
97 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
98 if (Invalid || !SEntry.isFile())
101 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
102 switch (IndexOpts.SystemSymbolFilter) {
103 case IndexingOptions::SystemSymbolFilterKind::None:
105 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
106 case IndexingOptions::SystemSymbolFilterKind::All:
111 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
112 if (ImportD->isImplicit())
113 Roles |= (unsigned)SymbolRole::Implicit;
115 return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
118 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
119 TemplateSpecializationKind TKind = TSK_Undeclared;
120 if (const ClassTemplateSpecializationDecl *
121 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
122 TKind = SD->getSpecializationKind();
123 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
124 TKind = FD->getTemplateSpecializationKind();
125 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
126 TKind = VD->getTemplateSpecializationKind();
127 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
128 if (RD->getInstantiatedFromMemberClass())
129 TKind = RD->getTemplateSpecializationKind();
130 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
131 if (ED->getInstantiatedFromMemberEnum())
132 TKind = ED->getTemplateSpecializationKind();
133 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
134 isa<EnumConstantDecl>(D)) {
135 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
136 return isTemplateImplicitInstantiation(Parent);
140 case TSK_ExplicitSpecialization:
142 case TSK_ImplicitInstantiation:
143 case TSK_ExplicitInstantiationDeclaration:
144 case TSK_ExplicitInstantiationDefinition:
147 llvm_unreachable("invalid TemplateSpecializationKind");
150 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
151 if (isa<ObjCInterfaceDecl>(D))
153 if (isa<ObjCCategoryDecl>(D))
155 if (isa<ObjCIvarDecl>(D))
157 if (isa<ObjCMethodDecl>(D))
159 if (isa<ImportDecl>(D))
164 static const CXXRecordDecl *
165 getDeclContextForTemplateInstationPattern(const Decl *D) {
166 if (const auto *CTSD =
167 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
168 return CTSD->getTemplateInstantiationPattern();
169 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
170 return RD->getInstantiatedFromMemberClass();
174 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
175 if (const ClassTemplateSpecializationDecl *
176 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
177 return SD->getTemplateInstantiationPattern();
178 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
179 return FD->getTemplateInstantiationPattern();
180 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
181 return VD->getTemplateInstantiationPattern();
182 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
183 return RD->getInstantiatedFromMemberClass();
184 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
185 return ED->getInstantiatedFromMemberEnum();
186 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
187 const auto *ND = cast<NamedDecl>(D);
188 if (const CXXRecordDecl *Pattern =
189 getDeclContextForTemplateInstationPattern(ND)) {
190 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
191 if (BaseND->isImplicit())
193 if (BaseND->getKind() == ND->getKind())
197 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
198 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
199 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
200 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
208 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
209 if (auto VD = dyn_cast<VarDecl>(D))
210 return VD->isThisDeclarationADefinition(Ctx);
212 if (auto FD = dyn_cast<FunctionDecl>(D))
213 return FD->isThisDeclarationADefinition();
215 if (auto TD = dyn_cast<TagDecl>(D))
216 return TD->isThisDeclarationADefinition();
218 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
219 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
221 if (isa<TypedefNameDecl>(D) ||
222 isa<EnumConstantDecl>(D) ||
224 isa<MSPropertyDecl>(D) ||
225 isa<ObjCImplDecl>(D) ||
226 isa<ObjCPropertyImplDecl>(D))
232 static const Decl *adjustParent(const Decl *Parent) {
235 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
236 if (isa<TranslationUnitDecl>(Parent))
238 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
240 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
241 if (NS->isAnonymousNamespace())
243 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
244 if (RD->isAnonymousStructOrUnion())
246 } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
247 if (FD->getDeclName().isEmpty())
254 static const Decl *getCanonicalDecl(const Decl *D) {
255 D = D->getCanonicalDecl();
256 if (auto TD = dyn_cast<TemplateDecl>(D)) {
257 D = TD->getTemplatedDecl();
258 assert(D->isCanonicalDecl());
264 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
265 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
269 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
271 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
273 case SymbolRole::RelationChildOf:
274 case SymbolRole::RelationBaseOf:
275 case SymbolRole::RelationOverrideOf:
276 case SymbolRole::RelationExtendedBy:
277 case SymbolRole::RelationAccessorOf:
278 case SymbolRole::RelationIBTypeOf:
281 case SymbolRole::Declaration:
282 case SymbolRole::Definition:
283 case SymbolRole::Reference:
284 case SymbolRole::Read:
285 case SymbolRole::Write:
286 case SymbolRole::Call:
287 case SymbolRole::Dynamic:
288 case SymbolRole::AddressOf:
289 case SymbolRole::Implicit:
290 case SymbolRole::RelationReceivedBy:
291 case SymbolRole::RelationCalledBy:
292 case SymbolRole::RelationContainedBy:
293 case SymbolRole::RelationSpecializationOf:
296 llvm_unreachable("Unsupported SymbolRole value!");
301 for (auto &Rel : Relations) {
302 if (acceptForRelation(Rel.Roles))
309 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
310 bool IsRef, const Decl *Parent,
312 ArrayRef<SymbolRelation> Relations,
315 const DeclContext *ContainerDC) {
316 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
318 if (!isa<NamedDecl>(D) ||
319 (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
320 !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
323 SourceManager &SM = Ctx->getSourceManager();
324 Loc = SM.getFileLoc(Loc);
330 std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
334 bool Invalid = false;
335 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
336 if (Invalid || !SEntry.isFile())
339 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
340 switch (IndexOpts.SystemSymbolFilter) {
341 case IndexingOptions::SystemSymbolFilterKind::None:
343 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
344 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
347 case IndexingOptions::SystemSymbolFilterKind::All:
352 if (isTemplateImplicitInstantiation(D)) {
355 D = adjustTemplateImplicitInstantiation(D);
358 assert(!isTemplateImplicitInstantiation(D));
365 Roles |= (unsigned)SymbolRole::Reference;
366 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
367 Roles |= (unsigned)SymbolRole::Definition;
369 Roles |= (unsigned)SymbolRole::Declaration;
371 D = getCanonicalDecl(D);
372 Parent = adjustParent(Parent);
374 Parent = getCanonicalDecl(Parent);
376 SmallVector<SymbolRelation, 6> FinalRelations;
377 FinalRelations.reserve(Relations.size()+1);
379 auto addRelation = [&](SymbolRelation Rel) {
380 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
381 [&](SymbolRelation Elem)->bool {
382 return Elem.RelatedSymbol == Rel.RelatedSymbol;
384 if (It != FinalRelations.end()) {
385 It->Roles |= Rel.Roles;
387 FinalRelations.push_back(Rel);
393 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
394 addRelation(SymbolRelation{
395 (unsigned)SymbolRole::RelationContainedBy,
399 addRelation(SymbolRelation{
400 (unsigned)SymbolRole::RelationChildOf,
406 for (auto &Rel : Relations) {
407 addRelation(SymbolRelation(Rel.Roles,
408 Rel.RelatedSymbol->getCanonicalDecl()));
411 IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
412 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,