150
|
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
|
|
21 static bool isGeneratedDecl(const Decl *D) {
|
|
22 if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
|
|
23 return attr->getGeneratedDeclaration();
|
|
24 }
|
|
25 return false;
|
|
26 }
|
|
27
|
|
28 bool IndexingContext::shouldIndex(const Decl *D) {
|
|
29 return !isGeneratedDecl(D);
|
|
30 }
|
|
31
|
|
32 const LangOptions &IndexingContext::getLangOpts() const {
|
|
33 return Ctx->getLangOpts();
|
|
34 }
|
|
35
|
|
36 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
|
|
37 return IndexOpts.IndexFunctionLocals;
|
|
38 }
|
|
39
|
|
40 bool IndexingContext::shouldIndexImplicitInstantiation() const {
|
|
41 return IndexOpts.IndexImplicitInstantiation;
|
|
42 }
|
|
43
|
|
44 bool IndexingContext::shouldIndexParametersInDeclarations() const {
|
|
45 return IndexOpts.IndexParametersInDeclarations;
|
|
46 }
|
|
47
|
|
48 bool IndexingContext::shouldIndexTemplateParameters() const {
|
|
49 return IndexOpts.IndexTemplateParameters;
|
|
50 }
|
|
51
|
|
52 bool IndexingContext::handleDecl(const Decl *D,
|
|
53 SymbolRoleSet Roles,
|
|
54 ArrayRef<SymbolRelation> Relations) {
|
|
55 return handleDecl(D, D->getLocation(), Roles, Relations);
|
|
56 }
|
|
57
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
173
|
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);
|
150
|
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
|
|
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 *
|
|
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
|
|
210 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
|
|
211 if (const ClassTemplateSpecializationDecl *
|
|
212 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
|
173
|
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();
|
150
|
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
|
|
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.
|
|
274 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
|
|
275 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
|
|
276 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
|
|
277 }
|
|
278
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 }
|