1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
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"
17
18 using namespace clang;
19 using namespace index;
20
isGeneratedDecl(const Decl * D)21 static bool isGeneratedDecl(const Decl *D) {
22 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23 return attr->getGeneratedDeclaration();
24 }
25 return false;
26 }
27
shouldIndex(const Decl * D)28 bool IndexingContext::shouldIndex(const Decl *D) {
29 return !isGeneratedDecl(D);
30 }
31
getLangOpts() const32 const LangOptions &IndexingContext::getLangOpts() const {
33 return Ctx->getLangOpts();
34 }
35
shouldIndexFunctionLocalSymbols() const36 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
37 return IndexOpts.IndexFunctionLocals;
38 }
39
shouldIndexImplicitInstantiation() const40 bool IndexingContext::shouldIndexImplicitInstantiation() const {
41 return IndexOpts.IndexImplicitInstantiation;
42 }
43
shouldIndexParametersInDeclarations() const44 bool IndexingContext::shouldIndexParametersInDeclarations() const {
45 return IndexOpts.IndexParametersInDeclarations;
46 }
47
shouldIndexTemplateParameters() const48 bool IndexingContext::shouldIndexTemplateParameters() const {
49 return IndexOpts.IndexTemplateParameters;
50 }
51
handleDecl(const Decl * D,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)52 bool IndexingContext::handleDecl(const Decl *D,
53 SymbolRoleSet Roles,
54 ArrayRef<SymbolRelation> Relations) {
55 return handleDecl(D, D->getLocation(), Roles, Relations);
56 }
57
handleDecl(const Decl * D,SourceLocation Loc,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const DeclContext * DC)58 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
59 SymbolRoleSet Roles,
60 ArrayRef<SymbolRelation> Relations,
61 const DeclContext *DC) {
62 if (!DC)
63 DC = D->getDeclContext();
64
65 const Decl *OrigD = D;
66 if (isa<ObjCPropertyImplDecl>(D)) {
67 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
68 }
69 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
70 Roles, Relations,
71 nullptr, OrigD, DC);
72 }
73
handleReference(const NamedDecl * D,SourceLocation Loc,const NamedDecl * Parent,const DeclContext * DC,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const Expr * RefE,const Decl * RefD)74 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
75 const NamedDecl *Parent,
76 const DeclContext *DC,
77 SymbolRoleSet Roles,
78 ArrayRef<SymbolRelation> Relations,
79 const Expr *RefE,
80 const Decl *RefD) {
81 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
82 return true;
83
84 if (!shouldIndexTemplateParameters() &&
85 (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
86 isa<TemplateTemplateParmDecl>(D))) {
87 return true;
88 }
89
90 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
91 RefE, RefD, DC);
92 }
93
reportModuleReferences(const Module * Mod,ArrayRef<SourceLocation> IdLocs,const ImportDecl * ImportD,IndexDataConsumer & DataConsumer)94 static void reportModuleReferences(const Module *Mod,
95 ArrayRef<SourceLocation> IdLocs,
96 const ImportDecl *ImportD,
97 IndexDataConsumer &DataConsumer) {
98 if (!Mod)
99 return;
100 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
101 DataConsumer);
102 DataConsumer.handleModuleOccurrence(
103 ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
104 }
105
importedModule(const ImportDecl * ImportD)106 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
107 if (ImportD->isInvalidDecl())
108 return true;
109
110 SourceLocation Loc;
111 auto IdLocs = ImportD->getIdentifierLocs();
112 if (!IdLocs.empty())
113 Loc = IdLocs.back();
114 else
115 Loc = ImportD->getLocation();
116
117 SourceManager &SM = Ctx->getSourceManager();
118 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
119 if (FID.isInvalid())
120 return true;
121
122 bool Invalid = false;
123 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
124 if (Invalid || !SEntry.isFile())
125 return true;
126
127 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
128 switch (IndexOpts.SystemSymbolFilter) {
129 case IndexingOptions::SystemSymbolFilterKind::None:
130 return true;
131 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
132 case IndexingOptions::SystemSymbolFilterKind::All:
133 break;
134 }
135 }
136
137 const Module *Mod = ImportD->getImportedModule();
138 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
139 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
140 DataConsumer);
141 }
142
143 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
144 if (ImportD->isImplicit())
145 Roles |= (unsigned)SymbolRole::Implicit;
146
147 return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
148 }
149
isTemplateImplicitInstantiation(const Decl * D)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);
169 }
170 switch (TKind) {
171 case TSK_Undeclared:
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:
177 return false;
178 case TSK_ImplicitInstantiation:
179 case TSK_ExplicitInstantiationDeclaration:
180 case TSK_ExplicitInstantiationDefinition:
181 return true;
182 }
183 llvm_unreachable("invalid TemplateSpecializationKind");
184 }
185
shouldIgnoreIfImplicit(const Decl * D)186 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
187 if (isa<ObjCInterfaceDecl>(D))
188 return false;
189 if (isa<ObjCCategoryDecl>(D))
190 return false;
191 if (isa<ObjCIvarDecl>(D))
192 return false;
193 if (isa<ObjCMethodDecl>(D))
194 return false;
195 if (isa<ImportDecl>(D))
196 return false;
197 return true;
198 }
199
200 static const CXXRecordDecl *
getDeclContextForTemplateInstationPattern(const Decl * D)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();
207 return nullptr;
208 }
209
adjustTemplateImplicitInstantiation(const Decl * D)210 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
211 if (const ClassTemplateSpecializationDecl *
212 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
213 const auto *Template = SD->getTemplateInstantiationPattern();
214 if (Template)
215 return Template;
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())
233 continue;
234 if (BaseND->getKind() == ND->getKind())
235 return BaseND;
236 }
237 }
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()))
242 return BaseECD;
243 }
244 }
245 }
246 return nullptr;
247 }
248
isDeclADefinition(const Decl * D,const DeclContext * ContainerDC,ASTContext & Ctx)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);
252
253 if (auto FD = dyn_cast<FunctionDecl>(D))
254 return FD->isThisDeclarationADefinition();
255
256 if (auto TD = dyn_cast<TagDecl>(D))
257 return TD->isThisDeclarationADefinition();
258
259 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
260 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
261
262 if (isa<TypedefNameDecl>(D) ||
263 isa<EnumConstantDecl>(D) ||
264 isa<FieldDecl>(D) ||
265 isa<MSPropertyDecl>(D) ||
266 isa<ObjCImplDecl>(D) ||
267 isa<ObjCPropertyImplDecl>(D))
268 return true;
269
270 return false;
271 }
272
273 /// Whether the given NamedDecl should be skipped because it has no name.
shouldSkipNamelessDecl(const NamedDecl * ND)274 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
275 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
276 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
277 }
278
adjustParent(const Decl * Parent)279 static const Decl *adjustParent(const Decl *Parent) {
280 if (!Parent)
281 return nullptr;
282 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
283 if (isa<TranslationUnitDecl>(Parent))
284 return nullptr;
285 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
286 continue;
287 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
288 if (NS->isAnonymousNamespace())
289 continue;
290 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
291 if (RD->isAnonymousStructOrUnion())
292 continue;
293 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
294 if (shouldSkipNamelessDecl(ND))
295 continue;
296 }
297 return Parent;
298 }
299 }
300
getCanonicalDecl(const Decl * D)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()) {
305 D = TTD;
306 assert(D->isCanonicalDecl());
307 }
308 }
309
310 return D;
311 }
312
shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)313 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
314 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
315 if (!IsRef)
316 return true;
317
318 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
319 bool accept = false;
320 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
321 switch (r) {
322 case SymbolRole::RelationChildOf:
323 case SymbolRole::RelationBaseOf:
324 case SymbolRole::RelationOverrideOf:
325 case SymbolRole::RelationExtendedBy:
326 case SymbolRole::RelationAccessorOf:
327 case SymbolRole::RelationIBTypeOf:
328 accept = true;
329 return false;
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:
345 return true;
346 }
347 llvm_unreachable("Unsupported SymbolRole value!");
348 });
349 return accept;
350 };
351
352 for (auto &Rel : Relations) {
353 if (acceptForRelation(Rel.Roles))
354 return true;
355 }
356
357 return false;
358 }
359
handleDeclOccurrence(const Decl * D,SourceLocation Loc,bool IsRef,const Decl * Parent,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const Expr * OrigE,const Decl * OrigD,const DeclContext * ContainerDC)360 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
361 bool IsRef, const Decl *Parent,
362 SymbolRoleSet Roles,
363 ArrayRef<SymbolRelation> Relations,
364 const Expr *OrigE,
365 const Decl *OrigD,
366 const DeclContext *ContainerDC) {
367 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
368 return true;
369 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
370 return true;
371
372 SourceManager &SM = Ctx->getSourceManager();
373 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
374 if (FID.isInvalid())
375 return true;
376
377 bool Invalid = false;
378 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
379 if (Invalid || !SEntry.isFile())
380 return true;
381
382 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
383 switch (IndexOpts.SystemSymbolFilter) {
384 case IndexingOptions::SystemSymbolFilterKind::None:
385 return true;
386 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
387 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
388 return true;
389 break;
390 case IndexingOptions::SystemSymbolFilterKind::All:
391 break;
392 }
393 }
394
395 if (!OrigD)
396 OrigD = D;
397
398 if (isTemplateImplicitInstantiation(D)) {
399 if (!IsRef)
400 return true;
401 D = adjustTemplateImplicitInstantiation(D);
402 if (!D)
403 return true;
404 assert(!isTemplateImplicitInstantiation(D));
405 }
406
407 if (IsRef)
408 Roles |= (unsigned)SymbolRole::Reference;
409 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
410 Roles |= (unsigned)SymbolRole::Definition;
411 else
412 Roles |= (unsigned)SymbolRole::Declaration;
413
414 D = getCanonicalDecl(D);
415 Parent = adjustParent(Parent);
416 if (Parent)
417 Parent = getCanonicalDecl(Parent);
418
419 SmallVector<SymbolRelation, 6> FinalRelations;
420 FinalRelations.reserve(Relations.size()+1);
421
422 auto addRelation = [&](SymbolRelation Rel) {
423 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
424 return Elem.RelatedSymbol == Rel.RelatedSymbol;
425 });
426 if (It != FinalRelations.end()) {
427 It->Roles |= Rel.Roles;
428 } else {
429 FinalRelations.push_back(Rel);
430 }
431 Roles |= Rel.Roles;
432 };
433
434 if (Parent) {
435 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
436 addRelation(SymbolRelation{
437 (unsigned)SymbolRole::RelationContainedBy,
438 Parent
439 });
440 } else {
441 addRelation(SymbolRelation{
442 (unsigned)SymbolRole::RelationChildOf,
443 Parent
444 });
445 }
446 }
447
448 for (auto &Rel : Relations) {
449 addRelation(SymbolRelation(Rel.Roles,
450 Rel.RelatedSymbol->getCanonicalDecl()));
451 }
452
453 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
454 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
455 }
456
handleMacroDefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)457 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
458 SourceLocation Loc,
459 const MacroInfo &MI) {
460 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
461 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
462 }
463
handleMacroUndefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)464 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
465 SourceLocation Loc,
466 const MacroInfo &MI) {
467 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
468 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
469 }
470
handleMacroReference(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)471 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
472 SourceLocation Loc,
473 const MacroInfo &MI) {
474 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
475 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
476 }
477