Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Index/IndexingContext.cpp
35234 views
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
if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
81
return true;
82
83
if (!shouldIndexTemplateParameters() &&
84
(isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
85
isa<TemplateTemplateParmDecl>(D))) {
86
return true;
87
}
88
return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
89
RefE, nullptr, DC);
90
}
91
92
static void reportModuleReferences(const Module *Mod,
93
ArrayRef<SourceLocation> IdLocs,
94
const ImportDecl *ImportD,
95
IndexDataConsumer &DataConsumer) {
96
if (!Mod)
97
return;
98
reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
99
DataConsumer);
100
DataConsumer.handleModuleOccurrence(
101
ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
102
}
103
104
bool IndexingContext::importedModule(const ImportDecl *ImportD) {
105
if (ImportD->isInvalidDecl())
106
return true;
107
108
SourceLocation Loc;
109
auto IdLocs = ImportD->getIdentifierLocs();
110
if (!IdLocs.empty())
111
Loc = IdLocs.back();
112
else
113
Loc = ImportD->getLocation();
114
115
SourceManager &SM = Ctx->getSourceManager();
116
FileID FID = SM.getFileID(SM.getFileLoc(Loc));
117
if (FID.isInvalid())
118
return true;
119
120
bool Invalid = false;
121
const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
122
if (Invalid || !SEntry.isFile())
123
return true;
124
125
if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
126
switch (IndexOpts.SystemSymbolFilter) {
127
case IndexingOptions::SystemSymbolFilterKind::None:
128
return true;
129
case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
130
case IndexingOptions::SystemSymbolFilterKind::All:
131
break;
132
}
133
}
134
135
const Module *Mod = ImportD->getImportedModule();
136
if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
137
reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
138
DataConsumer);
139
}
140
141
SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
142
if (ImportD->isImplicit())
143
Roles |= (unsigned)SymbolRole::Implicit;
144
145
return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
146
}
147
148
bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
149
TemplateSpecializationKind TKind = TSK_Undeclared;
150
if (const ClassTemplateSpecializationDecl *
151
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
152
TKind = SD->getSpecializationKind();
153
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
154
TKind = FD->getTemplateSpecializationKind();
155
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
156
TKind = VD->getTemplateSpecializationKind();
157
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
158
if (RD->getInstantiatedFromMemberClass())
159
TKind = RD->getTemplateSpecializationKind();
160
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
161
if (ED->getInstantiatedFromMemberEnum())
162
TKind = ED->getTemplateSpecializationKind();
163
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
164
isa<EnumConstantDecl>(D)) {
165
if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
166
return isTemplateImplicitInstantiation(Parent);
167
}
168
switch (TKind) {
169
case TSK_Undeclared:
170
// Instantiation maybe not happen yet when we see a SpecializationDecl,
171
// e.g. when the type doesn't need to be complete, we still treat it as an
172
// instantiation as we'd like to keep the canonicalized result consistent.
173
return isa<ClassTemplateSpecializationDecl>(D);
174
case TSK_ExplicitSpecialization:
175
return false;
176
case TSK_ImplicitInstantiation:
177
case TSK_ExplicitInstantiationDeclaration:
178
case TSK_ExplicitInstantiationDefinition:
179
return true;
180
}
181
llvm_unreachable("invalid TemplateSpecializationKind");
182
}
183
184
bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
185
if (isa<ObjCInterfaceDecl>(D))
186
return false;
187
if (isa<ObjCCategoryDecl>(D))
188
return false;
189
if (isa<ObjCIvarDecl>(D))
190
return false;
191
if (isa<ObjCMethodDecl>(D))
192
return false;
193
if (isa<ImportDecl>(D))
194
return false;
195
return true;
196
}
197
198
static const CXXRecordDecl *
199
getDeclContextForTemplateInstationPattern(const Decl *D) {
200
if (const auto *CTSD =
201
dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
202
return CTSD->getTemplateInstantiationPattern();
203
else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
204
return RD->getInstantiatedFromMemberClass();
205
return nullptr;
206
}
207
208
static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
209
if (const ClassTemplateSpecializationDecl *
210
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
211
const auto *Template = SD->getTemplateInstantiationPattern();
212
if (Template)
213
return Template;
214
// Fallback to primary template if no instantiation is available yet (e.g.
215
// the type doesn't need to be complete).
216
return SD->getSpecializedTemplate()->getTemplatedDecl();
217
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
218
return FD->getTemplateInstantiationPattern();
219
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
220
return VD->getTemplateInstantiationPattern();
221
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
222
return RD->getInstantiatedFromMemberClass();
223
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
224
return ED->getInstantiatedFromMemberEnum();
225
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
226
const auto *ND = cast<NamedDecl>(D);
227
if (const CXXRecordDecl *Pattern =
228
getDeclContextForTemplateInstationPattern(ND)) {
229
for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
230
if (BaseND->isImplicit())
231
continue;
232
if (BaseND->getKind() == ND->getKind())
233
return BaseND;
234
}
235
}
236
} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
237
if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
238
if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
239
for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
240
return BaseECD;
241
}
242
}
243
}
244
return nullptr;
245
}
246
247
static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
248
if (auto VD = dyn_cast<VarDecl>(D))
249
return VD->isThisDeclarationADefinition(Ctx);
250
251
if (auto FD = dyn_cast<FunctionDecl>(D))
252
return FD->isThisDeclarationADefinition();
253
254
if (auto TD = dyn_cast<TagDecl>(D))
255
return TD->isThisDeclarationADefinition();
256
257
if (auto MD = dyn_cast<ObjCMethodDecl>(D))
258
return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
259
260
if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||
261
isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||
262
isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))
263
return true;
264
265
return false;
266
}
267
268
/// Whether the given NamedDecl should be skipped because it has no name.
269
static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
270
return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
271
!isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
272
}
273
274
static const Decl *adjustParent(const Decl *Parent) {
275
if (!Parent)
276
return nullptr;
277
for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
278
if (isa<TranslationUnitDecl>(Parent))
279
return nullptr;
280
if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
281
continue;
282
if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
283
if (NS->isAnonymousNamespace())
284
continue;
285
} else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
286
if (RD->isAnonymousStructOrUnion())
287
continue;
288
} else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
289
if (shouldSkipNamelessDecl(ND))
290
continue;
291
}
292
return Parent;
293
}
294
}
295
296
static const Decl *getCanonicalDecl(const Decl *D) {
297
D = D->getCanonicalDecl();
298
if (auto TD = dyn_cast<TemplateDecl>(D)) {
299
if (auto TTD = TD->getTemplatedDecl()) {
300
D = TTD;
301
assert(D->isCanonicalDecl());
302
}
303
}
304
305
return D;
306
}
307
308
static bool shouldReportOccurrenceForSystemDeclOnlyMode(
309
bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
310
if (!IsRef)
311
return true;
312
313
auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
314
bool accept = false;
315
applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
316
switch (r) {
317
case SymbolRole::RelationChildOf:
318
case SymbolRole::RelationBaseOf:
319
case SymbolRole::RelationOverrideOf:
320
case SymbolRole::RelationExtendedBy:
321
case SymbolRole::RelationAccessorOf:
322
case SymbolRole::RelationIBTypeOf:
323
accept = true;
324
return false;
325
case SymbolRole::Declaration:
326
case SymbolRole::Definition:
327
case SymbolRole::Reference:
328
case SymbolRole::Read:
329
case SymbolRole::Write:
330
case SymbolRole::Call:
331
case SymbolRole::Dynamic:
332
case SymbolRole::AddressOf:
333
case SymbolRole::Implicit:
334
case SymbolRole::Undefinition:
335
case SymbolRole::RelationReceivedBy:
336
case SymbolRole::RelationCalledBy:
337
case SymbolRole::RelationContainedBy:
338
case SymbolRole::RelationSpecializationOf:
339
case SymbolRole::NameReference:
340
return true;
341
}
342
llvm_unreachable("Unsupported SymbolRole value!");
343
});
344
return accept;
345
};
346
347
for (auto &Rel : Relations) {
348
if (acceptForRelation(Rel.Roles))
349
return true;
350
}
351
352
return false;
353
}
354
355
bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
356
bool IsRef, const Decl *Parent,
357
SymbolRoleSet Roles,
358
ArrayRef<SymbolRelation> Relations,
359
const Expr *OrigE,
360
const Decl *OrigD,
361
const DeclContext *ContainerDC) {
362
if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
363
return true;
364
if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
365
return true;
366
367
SourceManager &SM = Ctx->getSourceManager();
368
FileID FID = SM.getFileID(SM.getFileLoc(Loc));
369
if (FID.isInvalid())
370
return true;
371
372
bool Invalid = false;
373
const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
374
if (Invalid || !SEntry.isFile())
375
return true;
376
377
if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
378
switch (IndexOpts.SystemSymbolFilter) {
379
case IndexingOptions::SystemSymbolFilterKind::None:
380
return true;
381
case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
382
if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
383
return true;
384
break;
385
case IndexingOptions::SystemSymbolFilterKind::All:
386
break;
387
}
388
}
389
390
if (!OrigD)
391
OrigD = D;
392
393
if (isTemplateImplicitInstantiation(D)) {
394
if (!IsRef)
395
return true;
396
D = adjustTemplateImplicitInstantiation(D);
397
if (!D)
398
return true;
399
assert(!isTemplateImplicitInstantiation(D));
400
}
401
402
if (IsRef)
403
Roles |= (unsigned)SymbolRole::Reference;
404
else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
405
Roles |= (unsigned)SymbolRole::Definition;
406
else
407
Roles |= (unsigned)SymbolRole::Declaration;
408
409
D = getCanonicalDecl(D);
410
Parent = adjustParent(Parent);
411
if (Parent)
412
Parent = getCanonicalDecl(Parent);
413
414
SmallVector<SymbolRelation, 6> FinalRelations;
415
FinalRelations.reserve(Relations.size()+1);
416
417
auto addRelation = [&](SymbolRelation Rel) {
418
auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
419
return Elem.RelatedSymbol == Rel.RelatedSymbol;
420
});
421
if (It != FinalRelations.end()) {
422
It->Roles |= Rel.Roles;
423
} else {
424
FinalRelations.push_back(Rel);
425
}
426
Roles |= Rel.Roles;
427
};
428
429
if (Parent) {
430
if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
431
addRelation(SymbolRelation{
432
(unsigned)SymbolRole::RelationContainedBy,
433
Parent
434
});
435
} else {
436
addRelation(SymbolRelation{
437
(unsigned)SymbolRole::RelationChildOf,
438
Parent
439
});
440
}
441
}
442
443
for (auto &Rel : Relations) {
444
addRelation(SymbolRelation(Rel.Roles,
445
Rel.RelatedSymbol->getCanonicalDecl()));
446
}
447
448
IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
449
return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
450
}
451
452
void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
453
SourceLocation Loc,
454
const MacroInfo &MI) {
455
if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
456
return;
457
SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
458
DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
459
}
460
461
void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
462
SourceLocation Loc,
463
const MacroInfo &MI) {
464
if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
465
return;
466
SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
467
DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
468
}
469
470
void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
471
SourceLocation Loc,
472
const MacroInfo &MI) {
473
if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
474
return;
475
SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
476
DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
477
}
478
479
bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
480
SourceLocation Loc) {
481
if (!IndexOpts.IndexMacros)
482
return false;
483
484
switch (IndexOpts.SystemSymbolFilter) {
485
case IndexingOptions::SystemSymbolFilterKind::None:
486
break;
487
case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
488
if (!IsRef)
489
return true;
490
break;
491
case IndexingOptions::SystemSymbolFilterKind::All:
492
return true;
493
}
494
495
SourceManager &SM = Ctx->getSourceManager();
496
FileID FID = SM.getFileID(SM.getFileLoc(Loc));
497
if (FID.isInvalid())
498
return false;
499
500
bool Invalid = false;
501
const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
502
if (Invalid || !SEntry.isFile())
503
return false;
504
505
return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
506
}
507
508