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