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