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:
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 
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)) {
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 
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   if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
461     return;
462   SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
463   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
464 }
465 
466 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
467                                            SourceLocation Loc,
468                                            const MacroInfo &MI) {
469   if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
470     return;
471   SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
472   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
473 }
474 
475 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
476                                            SourceLocation Loc,
477                                            const MacroInfo &MI) {
478   if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
479     return;
480   SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
481   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
482 }
483 
484 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
485                                                  SourceLocation Loc) {
486   if (!IndexOpts.IndexMacros)
487     return false;
488 
489   switch (IndexOpts.SystemSymbolFilter) {
490   case IndexingOptions::SystemSymbolFilterKind::None:
491     break;
492   case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
493     if (!IsRef)
494       return true;
495     break;
496   case IndexingOptions::SystemSymbolFilterKind::All:
497     return true;
498   }
499 
500   SourceManager &SM = Ctx->getSourceManager();
501   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
502   if (FID.isInvalid())
503     return false;
504 
505   bool Invalid = false;
506   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
507   if (Invalid || !SEntry.isFile())
508     return false;
509 
510   return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
511 }
512