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 case TSK_ExplicitSpecialization:
173 return false;
174 case TSK_ImplicitInstantiation:
175 case TSK_ExplicitInstantiationDeclaration:
176 case TSK_ExplicitInstantiationDefinition:
177 return true;
178 }
179 llvm_unreachable("invalid TemplateSpecializationKind");
180 }
181
shouldIgnoreIfImplicit(const Decl * D)182 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
183 if (isa<ObjCInterfaceDecl>(D))
184 return false;
185 if (isa<ObjCCategoryDecl>(D))
186 return false;
187 if (isa<ObjCIvarDecl>(D))
188 return false;
189 if (isa<ObjCMethodDecl>(D))
190 return false;
191 if (isa<ImportDecl>(D))
192 return false;
193 return true;
194 }
195
196 static const CXXRecordDecl *
getDeclContextForTemplateInstationPattern(const Decl * D)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();
203 return nullptr;
204 }
205
adjustTemplateImplicitInstantiation(const Decl * D)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())
224 continue;
225 if (BaseND->getKind() == ND->getKind())
226 return BaseND;
227 }
228 }
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()))
233 return BaseECD;
234 }
235 }
236 }
237 return nullptr;
238 }
239
isDeclADefinition(const Decl * D,const DeclContext * ContainerDC,ASTContext & Ctx)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);
243
244 if (auto FD = dyn_cast<FunctionDecl>(D))
245 return FD->isThisDeclarationADefinition();
246
247 if (auto TD = dyn_cast<TagDecl>(D))
248 return TD->isThisDeclarationADefinition();
249
250 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
251 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
252
253 if (isa<TypedefNameDecl>(D) ||
254 isa<EnumConstantDecl>(D) ||
255 isa<FieldDecl>(D) ||
256 isa<MSPropertyDecl>(D) ||
257 isa<ObjCImplDecl>(D) ||
258 isa<ObjCPropertyImplDecl>(D))
259 return true;
260
261 return false;
262 }
263
264 /// Whether the given NamedDecl should be skipped because it has no name.
shouldSkipNamelessDecl(const NamedDecl * ND)265 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
266 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
267 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
268 }
269
adjustParent(const Decl * Parent)270 static const Decl *adjustParent(const Decl *Parent) {
271 if (!Parent)
272 return nullptr;
273 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
274 if (isa<TranslationUnitDecl>(Parent))
275 return nullptr;
276 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
277 continue;
278 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
279 if (NS->isAnonymousNamespace())
280 continue;
281 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
282 if (RD->isAnonymousStructOrUnion())
283 continue;
284 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
285 if (shouldSkipNamelessDecl(ND))
286 continue;
287 }
288 return Parent;
289 }
290 }
291
getCanonicalDecl(const Decl * D)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()) {
296 D = TTD;
297 assert(D->isCanonicalDecl());
298 }
299 }
300
301 return D;
302 }
303
shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)304 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
305 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
306 if (!IsRef)
307 return true;
308
309 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
310 bool accept = false;
311 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
312 switch (r) {
313 case SymbolRole::RelationChildOf:
314 case SymbolRole::RelationBaseOf:
315 case SymbolRole::RelationOverrideOf:
316 case SymbolRole::RelationExtendedBy:
317 case SymbolRole::RelationAccessorOf:
318 case SymbolRole::RelationIBTypeOf:
319 accept = true;
320 return false;
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:
336 return true;
337 }
338 llvm_unreachable("Unsupported SymbolRole value!");
339 });
340 return accept;
341 };
342
343 for (auto &Rel : Relations) {
344 if (acceptForRelation(Rel.Roles))
345 return true;
346 }
347
348 return false;
349 }
350
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)351 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
352 bool IsRef, const Decl *Parent,
353 SymbolRoleSet Roles,
354 ArrayRef<SymbolRelation> Relations,
355 const Expr *OrigE,
356 const Decl *OrigD,
357 const DeclContext *ContainerDC) {
358 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
359 return true;
360 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
361 return true;
362
363 SourceManager &SM = Ctx->getSourceManager();
364 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
365 if (FID.isInvalid())
366 return true;
367
368 bool Invalid = false;
369 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
370 if (Invalid || !SEntry.isFile())
371 return true;
372
373 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
374 switch (IndexOpts.SystemSymbolFilter) {
375 case IndexingOptions::SystemSymbolFilterKind::None:
376 return true;
377 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
378 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
379 return true;
380 break;
381 case IndexingOptions::SystemSymbolFilterKind::All:
382 break;
383 }
384 }
385
386 if (!OrigD)
387 OrigD = D;
388
389 if (isTemplateImplicitInstantiation(D)) {
390 if (!IsRef)
391 return true;
392 D = adjustTemplateImplicitInstantiation(D);
393 if (!D)
394 return true;
395 assert(!isTemplateImplicitInstantiation(D));
396 }
397
398 if (IsRef)
399 Roles |= (unsigned)SymbolRole::Reference;
400 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
401 Roles |= (unsigned)SymbolRole::Definition;
402 else
403 Roles |= (unsigned)SymbolRole::Declaration;
404
405 D = getCanonicalDecl(D);
406 Parent = adjustParent(Parent);
407 if (Parent)
408 Parent = getCanonicalDecl(Parent);
409
410 SmallVector<SymbolRelation, 6> FinalRelations;
411 FinalRelations.reserve(Relations.size()+1);
412
413 auto addRelation = [&](SymbolRelation Rel) {
414 auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
415 return Elem.RelatedSymbol == Rel.RelatedSymbol;
416 });
417 if (It != FinalRelations.end()) {
418 It->Roles |= Rel.Roles;
419 } else {
420 FinalRelations.push_back(Rel);
421 }
422 Roles |= Rel.Roles;
423 };
424
425 if (Parent) {
426 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
427 addRelation(SymbolRelation{
428 (unsigned)SymbolRole::RelationContainedBy,
429 Parent
430 });
431 } else {
432 addRelation(SymbolRelation{
433 (unsigned)SymbolRole::RelationChildOf,
434 Parent
435 });
436 }
437 }
438
439 for (auto &Rel : Relations) {
440 addRelation(SymbolRelation(Rel.Roles,
441 Rel.RelatedSymbol->getCanonicalDecl()));
442 }
443
444 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
445 return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
446 }
447
handleMacroDefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)448 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
449 SourceLocation Loc,
450 const MacroInfo &MI) {
451 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
452 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
453 }
454
handleMacroUndefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)455 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
456 SourceLocation Loc,
457 const MacroInfo &MI) {
458 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
459 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
460 }
461
handleMacroReference(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)462 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
463 SourceLocation Loc,
464 const MacroInfo &MI) {
465 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
466 DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
467 }
468