xref: /freebsd/contrib/llvm-project/clang/lib/Index/IndexingContext.cpp (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
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