1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "IndexingContext.h"
11 #include "clang/Basic/SourceLocation.h"
12 #include "clang/Index/IndexDataConsumer.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/AST/DeclObjC.h"
16 #include "clang/Basic/SourceManager.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
handleDecl(const Decl * D,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)44 bool IndexingContext::handleDecl(const Decl *D,
45 SymbolRoleSet Roles,
46 ArrayRef<SymbolRelation> Relations) {
47 return handleDecl(D, D->getLocation(), Roles, Relations);
48 }
49
handleDecl(const Decl * D,SourceLocation Loc,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const DeclContext * DC)50 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
51 SymbolRoleSet Roles,
52 ArrayRef<SymbolRelation> Relations,
53 const DeclContext *DC) {
54 if (!DC)
55 DC = D->getDeclContext();
56
57 const Decl *OrigD = D;
58 if (isa<ObjCPropertyImplDecl>(D)) {
59 D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
60 }
61 return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
62 Roles, Relations,
63 nullptr, OrigD, DC);
64 }
65
handleReference(const NamedDecl * D,SourceLocation Loc,const NamedDecl * Parent,const DeclContext * DC,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations,const Expr * RefE,const Decl * RefD)66 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
67 const NamedDecl *Parent,
68 const DeclContext *DC,
69 SymbolRoleSet Roles,
70 ArrayRef<SymbolRelation> Relations,
71 const Expr *RefE,
72 const Decl *RefD) {
73 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
74 return true;
75
76 if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
77 return true;
78
79 return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
80 RefE, RefD, DC);
81 }
82
reportModuleReferences(const Module * Mod,ArrayRef<SourceLocation> IdLocs,const ImportDecl * ImportD,IndexDataConsumer & DataConsumer)83 static void reportModuleReferences(const Module *Mod,
84 ArrayRef<SourceLocation> IdLocs,
85 const ImportDecl *ImportD,
86 IndexDataConsumer &DataConsumer) {
87 if (!Mod)
88 return;
89 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
90 DataConsumer);
91 DataConsumer.handleModuleOccurence(ImportD, Mod,
92 (SymbolRoleSet)SymbolRole::Reference,
93 IdLocs.back());
94 }
95
importedModule(const ImportDecl * ImportD)96 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
97 if (ImportD->isInvalidDecl())
98 return true;
99
100 SourceLocation Loc;
101 auto IdLocs = ImportD->getIdentifierLocs();
102 if (!IdLocs.empty())
103 Loc = IdLocs.back();
104 else
105 Loc = ImportD->getLocation();
106
107 SourceManager &SM = Ctx->getSourceManager();
108 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
109 if (FID.isInvalid())
110 return true;
111
112 bool Invalid = false;
113 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
114 if (Invalid || !SEntry.isFile())
115 return true;
116
117 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
118 switch (IndexOpts.SystemSymbolFilter) {
119 case IndexingOptions::SystemSymbolFilterKind::None:
120 return true;
121 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
122 case IndexingOptions::SystemSymbolFilterKind::All:
123 break;
124 }
125 }
126
127 const Module *Mod = ImportD->getImportedModule();
128 if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
129 reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
130 DataConsumer);
131 }
132
133 SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
134 if (ImportD->isImplicit())
135 Roles |= (unsigned)SymbolRole::Implicit;
136
137 return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc);
138 }
139
isTemplateImplicitInstantiation(const Decl * D)140 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
141 TemplateSpecializationKind TKind = TSK_Undeclared;
142 if (const ClassTemplateSpecializationDecl *
143 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
144 TKind = SD->getSpecializationKind();
145 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
146 TKind = FD->getTemplateSpecializationKind();
147 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
148 TKind = VD->getTemplateSpecializationKind();
149 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
150 if (RD->getInstantiatedFromMemberClass())
151 TKind = RD->getTemplateSpecializationKind();
152 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
153 if (ED->getInstantiatedFromMemberEnum())
154 TKind = ED->getTemplateSpecializationKind();
155 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
156 isa<EnumConstantDecl>(D)) {
157 if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
158 return isTemplateImplicitInstantiation(Parent);
159 }
160 switch (TKind) {
161 case TSK_Undeclared:
162 case TSK_ExplicitSpecialization:
163 return false;
164 case TSK_ImplicitInstantiation:
165 case TSK_ExplicitInstantiationDeclaration:
166 case TSK_ExplicitInstantiationDefinition:
167 return true;
168 }
169 llvm_unreachable("invalid TemplateSpecializationKind");
170 }
171
shouldIgnoreIfImplicit(const Decl * D)172 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
173 if (isa<ObjCInterfaceDecl>(D))
174 return false;
175 if (isa<ObjCCategoryDecl>(D))
176 return false;
177 if (isa<ObjCIvarDecl>(D))
178 return false;
179 if (isa<ObjCMethodDecl>(D))
180 return false;
181 if (isa<ImportDecl>(D))
182 return false;
183 return true;
184 }
185
186 static const CXXRecordDecl *
getDeclContextForTemplateInstationPattern(const Decl * D)187 getDeclContextForTemplateInstationPattern(const Decl *D) {
188 if (const auto *CTSD =
189 dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
190 return CTSD->getTemplateInstantiationPattern();
191 else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
192 return RD->getInstantiatedFromMemberClass();
193 return nullptr;
194 }
195
adjustTemplateImplicitInstantiation(const Decl * D)196 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
197 if (const ClassTemplateSpecializationDecl *
198 SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
199 return SD->getTemplateInstantiationPattern();
200 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
201 return FD->getTemplateInstantiationPattern();
202 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
203 return VD->getTemplateInstantiationPattern();
204 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
205 return RD->getInstantiatedFromMemberClass();
206 } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
207 return ED->getInstantiatedFromMemberEnum();
208 } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
209 const auto *ND = cast<NamedDecl>(D);
210 if (const CXXRecordDecl *Pattern =
211 getDeclContextForTemplateInstationPattern(ND)) {
212 for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
213 if (BaseND->isImplicit())
214 continue;
215 if (BaseND->getKind() == ND->getKind())
216 return BaseND;
217 }
218 }
219 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
220 if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
221 if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
222 for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
223 return BaseECD;
224 }
225 }
226 }
227 return nullptr;
228 }
229
isDeclADefinition(const Decl * D,const DeclContext * ContainerDC,ASTContext & Ctx)230 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
231 if (auto VD = dyn_cast<VarDecl>(D))
232 return VD->isThisDeclarationADefinition(Ctx);
233
234 if (auto FD = dyn_cast<FunctionDecl>(D))
235 return FD->isThisDeclarationADefinition();
236
237 if (auto TD = dyn_cast<TagDecl>(D))
238 return TD->isThisDeclarationADefinition();
239
240 if (auto MD = dyn_cast<ObjCMethodDecl>(D))
241 return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
242
243 if (isa<TypedefNameDecl>(D) ||
244 isa<EnumConstantDecl>(D) ||
245 isa<FieldDecl>(D) ||
246 isa<MSPropertyDecl>(D) ||
247 isa<ObjCImplDecl>(D) ||
248 isa<ObjCPropertyImplDecl>(D))
249 return true;
250
251 return false;
252 }
253
254 /// Whether the given NamedDecl should be skipped because it has no name.
shouldSkipNamelessDecl(const NamedDecl * ND)255 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
256 return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
257 !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
258 }
259
adjustParent(const Decl * Parent)260 static const Decl *adjustParent(const Decl *Parent) {
261 if (!Parent)
262 return nullptr;
263 for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
264 if (isa<TranslationUnitDecl>(Parent))
265 return nullptr;
266 if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
267 continue;
268 if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
269 if (NS->isAnonymousNamespace())
270 continue;
271 } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
272 if (RD->isAnonymousStructOrUnion())
273 continue;
274 } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
275 if (shouldSkipNamelessDecl(ND))
276 continue;
277 }
278 return Parent;
279 }
280 }
281
getCanonicalDecl(const Decl * D)282 static const Decl *getCanonicalDecl(const Decl *D) {
283 D = D->getCanonicalDecl();
284 if (auto TD = dyn_cast<TemplateDecl>(D)) {
285 if (auto TTD = TD->getTemplatedDecl()) {
286 D = TTD;
287 assert(D->isCanonicalDecl());
288 }
289 }
290
291 return D;
292 }
293
shouldReportOccurrenceForSystemDeclOnlyMode(bool IsRef,SymbolRoleSet Roles,ArrayRef<SymbolRelation> Relations)294 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
295 bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
296 if (!IsRef)
297 return true;
298
299 auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
300 bool accept = false;
301 applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
302 switch (r) {
303 case SymbolRole::RelationChildOf:
304 case SymbolRole::RelationBaseOf:
305 case SymbolRole::RelationOverrideOf:
306 case SymbolRole::RelationExtendedBy:
307 case SymbolRole::RelationAccessorOf:
308 case SymbolRole::RelationIBTypeOf:
309 accept = true;
310 return false;
311 case SymbolRole::Declaration:
312 case SymbolRole::Definition:
313 case SymbolRole::Reference:
314 case SymbolRole::Read:
315 case SymbolRole::Write:
316 case SymbolRole::Call:
317 case SymbolRole::Dynamic:
318 case SymbolRole::AddressOf:
319 case SymbolRole::Implicit:
320 case SymbolRole::Undefinition:
321 case SymbolRole::RelationReceivedBy:
322 case SymbolRole::RelationCalledBy:
323 case SymbolRole::RelationContainedBy:
324 case SymbolRole::RelationSpecializationOf:
325 return true;
326 }
327 llvm_unreachable("Unsupported SymbolRole value!");
328 });
329 return accept;
330 };
331
332 for (auto &Rel : Relations) {
333 if (acceptForRelation(Rel.Roles))
334 return true;
335 }
336
337 return false;
338 }
339
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)340 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
341 bool IsRef, const Decl *Parent,
342 SymbolRoleSet Roles,
343 ArrayRef<SymbolRelation> Relations,
344 const Expr *OrigE,
345 const Decl *OrigD,
346 const DeclContext *ContainerDC) {
347 if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
348 return true;
349 if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
350 return true;
351
352 SourceManager &SM = Ctx->getSourceManager();
353 FileID FID = SM.getFileID(SM.getFileLoc(Loc));
354 if (FID.isInvalid())
355 return true;
356
357 bool Invalid = false;
358 const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
359 if (Invalid || !SEntry.isFile())
360 return true;
361
362 if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
363 switch (IndexOpts.SystemSymbolFilter) {
364 case IndexingOptions::SystemSymbolFilterKind::None:
365 return true;
366 case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
367 if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
368 return true;
369 break;
370 case IndexingOptions::SystemSymbolFilterKind::All:
371 break;
372 }
373 }
374
375 if (!OrigD)
376 OrigD = D;
377
378 if (isTemplateImplicitInstantiation(D)) {
379 if (!IsRef)
380 return true;
381 D = adjustTemplateImplicitInstantiation(D);
382 if (!D)
383 return true;
384 assert(!isTemplateImplicitInstantiation(D));
385 }
386
387 if (IsRef)
388 Roles |= (unsigned)SymbolRole::Reference;
389 else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
390 Roles |= (unsigned)SymbolRole::Definition;
391 else
392 Roles |= (unsigned)SymbolRole::Declaration;
393
394 D = getCanonicalDecl(D);
395 Parent = adjustParent(Parent);
396 if (Parent)
397 Parent = getCanonicalDecl(Parent);
398
399 SmallVector<SymbolRelation, 6> FinalRelations;
400 FinalRelations.reserve(Relations.size()+1);
401
402 auto addRelation = [&](SymbolRelation Rel) {
403 auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
404 [&](SymbolRelation Elem)->bool {
405 return Elem.RelatedSymbol == Rel.RelatedSymbol;
406 });
407 if (It != FinalRelations.end()) {
408 It->Roles |= Rel.Roles;
409 } else {
410 FinalRelations.push_back(Rel);
411 }
412 Roles |= Rel.Roles;
413 };
414
415 if (Parent) {
416 if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
417 addRelation(SymbolRelation{
418 (unsigned)SymbolRole::RelationContainedBy,
419 Parent
420 });
421 } else {
422 addRelation(SymbolRelation{
423 (unsigned)SymbolRole::RelationChildOf,
424 Parent
425 });
426 }
427 }
428
429 for (auto &Rel : Relations) {
430 addRelation(SymbolRelation(Rel.Roles,
431 Rel.RelatedSymbol->getCanonicalDecl()));
432 }
433
434 IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
435 return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
436 }
437
handleMacroDefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)438 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
439 SourceLocation Loc,
440 const MacroInfo &MI) {
441 SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
442 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
443 }
444
handleMacroUndefined(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)445 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
446 SourceLocation Loc,
447 const MacroInfo &MI) {
448 SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
449 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
450 }
451
handleMacroReference(const IdentifierInfo & Name,SourceLocation Loc,const MacroInfo & MI)452 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
453 SourceLocation Loc,
454 const MacroInfo &MI) {
455 SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
456 DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
457 }
458