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