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 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
21   return IndexOpts.IndexFunctionLocals;
22 }
23 
24 bool IndexingContext::handleDecl(const Decl *D,
25                                  SymbolRoleSet Roles,
26                                  ArrayRef<SymbolRelation> Relations) {
27   return handleDecl(D, D->getLocation(), Roles, Relations);
28 }
29 
30 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
31                                  SymbolRoleSet Roles,
32                                  ArrayRef<SymbolRelation> Relations,
33                                  const DeclContext *DC) {
34   if (!DC)
35     DC = D->getDeclContext();
36 
37   const Decl *OrigD = D;
38   if (isa<ObjCPropertyImplDecl>(D)) {
39     D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
40   }
41   return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
42                               Roles, Relations,
43                               nullptr, OrigD, DC);
44 }
45 
46 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
47                                       const NamedDecl *Parent,
48                                       const DeclContext *DC,
49                                       SymbolRoleSet Roles,
50                                       ArrayRef<SymbolRelation> Relations,
51                                       const Expr *RefE,
52                                       const Decl *RefD) {
53   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
54     return true;
55 
56   if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
57     return true;
58 
59   return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
60                               RefE, RefD, DC);
61 }
62 
63 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
64   SourceLocation Loc;
65   auto IdLocs = ImportD->getIdentifierLocs();
66   if (!IdLocs.empty())
67     Loc = IdLocs.front();
68   else
69     Loc = ImportD->getLocation();
70   SourceManager &SM = Ctx->getSourceManager();
71   Loc = SM.getFileLoc(Loc);
72   if (Loc.isInvalid())
73     return true;
74 
75   FileID FID;
76   unsigned Offset;
77   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
78   if (FID.isInvalid())
79     return true;
80 
81   bool Invalid = false;
82   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
83   if (Invalid || !SEntry.isFile())
84     return true;
85 
86   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
87     switch (IndexOpts.SystemSymbolFilter) {
88     case IndexingOptions::SystemSymbolFilterKind::None:
89       return true;
90     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
91     case IndexingOptions::SystemSymbolFilterKind::All:
92       break;
93     }
94   }
95 
96   SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
97   if (ImportD->isImplicit())
98     Roles |= (unsigned)SymbolRole::Implicit;
99 
100   return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
101 }
102 
103 bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
104   assert(D);
105 
106   if (isa<TemplateTemplateParmDecl>(D))
107     return true;
108 
109   if (isa<ObjCTypeParamDecl>(D))
110     return true;
111 
112   if (!D->getParentFunctionOrMethod())
113     return false;
114 
115   if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
116     switch (ND->getFormalLinkage()) {
117     case NoLinkage:
118     case VisibleNoLinkage:
119     case InternalLinkage:
120       return true;
121     case UniqueExternalLinkage:
122       llvm_unreachable("Not a sema linkage");
123     case ExternalLinkage:
124       return false;
125     }
126   }
127 
128   return true;
129 }
130 
131 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
132   TemplateSpecializationKind TKind = TSK_Undeclared;
133   if (const ClassTemplateSpecializationDecl *
134       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
135     TKind = SD->getSpecializationKind();
136   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
137     TKind = FD->getTemplateSpecializationKind();
138   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
139     TKind = VD->getTemplateSpecializationKind();
140   }
141   switch (TKind) {
142     case TSK_Undeclared:
143     case TSK_ExplicitSpecialization:
144       return false;
145     case TSK_ImplicitInstantiation:
146     case TSK_ExplicitInstantiationDeclaration:
147     case TSK_ExplicitInstantiationDefinition:
148       return true;
149   }
150   llvm_unreachable("invalid TemplateSpecializationKind");
151 }
152 
153 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
154   if (isa<ObjCInterfaceDecl>(D))
155     return false;
156   if (isa<ObjCCategoryDecl>(D))
157     return false;
158   if (isa<ObjCIvarDecl>(D))
159     return false;
160   if (isa<ObjCMethodDecl>(D))
161     return false;
162   if (isa<ImportDecl>(D))
163     return false;
164   return true;
165 }
166 
167 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
168   if (const ClassTemplateSpecializationDecl *
169       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
170     return SD->getTemplateInstantiationPattern();
171   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
172     return FD->getTemplateInstantiationPattern();
173   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
174     return VD->getTemplateInstantiationPattern();
175   }
176   return nullptr;
177 }
178 
179 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
180   if (auto VD = dyn_cast<VarDecl>(D))
181     return VD->isThisDeclarationADefinition(Ctx);
182 
183   if (auto FD = dyn_cast<FunctionDecl>(D))
184     return FD->isThisDeclarationADefinition();
185 
186   if (auto TD = dyn_cast<TagDecl>(D))
187     return TD->isThisDeclarationADefinition();
188 
189   if (auto MD = dyn_cast<ObjCMethodDecl>(D))
190     return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
191 
192   if (isa<TypedefNameDecl>(D) ||
193       isa<EnumConstantDecl>(D) ||
194       isa<FieldDecl>(D) ||
195       isa<MSPropertyDecl>(D) ||
196       isa<ObjCImplDecl>(D) ||
197       isa<ObjCPropertyImplDecl>(D))
198     return true;
199 
200   return false;
201 }
202 
203 static const Decl *adjustParent(const Decl *Parent) {
204   if (!Parent)
205     return nullptr;
206   for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
207     if (isa<TranslationUnitDecl>(Parent))
208       return nullptr;
209     if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
210       continue;
211     if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
212       if (NS->isAnonymousNamespace())
213         continue;
214     } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
215       if (RD->isAnonymousStructOrUnion())
216         continue;
217     } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
218       if (FD->getDeclName().isEmpty())
219         continue;
220     }
221     return Parent;
222   }
223 }
224 
225 static const Decl *getCanonicalDecl(const Decl *D) {
226   D = D->getCanonicalDecl();
227   if (auto TD = dyn_cast<TemplateDecl>(D)) {
228     D = TD->getTemplatedDecl();
229     assert(D->isCanonicalDecl());
230   }
231 
232   return D;
233 }
234 
235 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
236                                            bool IsRef, const Decl *Parent,
237                                            SymbolRoleSet Roles,
238                                            ArrayRef<SymbolRelation> Relations,
239                                            const Expr *OrigE,
240                                            const Decl *OrigD,
241                                            const DeclContext *ContainerDC) {
242   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
243     return true;
244   if (!isa<NamedDecl>(D) ||
245       (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
246        !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
247     return true;
248 
249   SourceManager &SM = Ctx->getSourceManager();
250   Loc = SM.getFileLoc(Loc);
251   if (Loc.isInvalid())
252     return true;
253 
254   FileID FID;
255   unsigned Offset;
256   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
257   if (FID.isInvalid())
258     return true;
259 
260   bool Invalid = false;
261   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
262   if (Invalid || !SEntry.isFile())
263     return true;
264 
265   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
266     switch (IndexOpts.SystemSymbolFilter) {
267     case IndexingOptions::SystemSymbolFilterKind::None:
268       return true;
269     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
270       if (IsRef)
271         return true;
272       break;
273     case IndexingOptions::SystemSymbolFilterKind::All:
274       break;
275     }
276   }
277 
278   if (isTemplateImplicitInstantiation(D)) {
279     if (!IsRef)
280       return true;
281     D = adjustTemplateImplicitInstantiation(D);
282     if (!D)
283       return true;
284     assert(!isTemplateImplicitInstantiation(D));
285   }
286 
287   if (!OrigD)
288     OrigD = D;
289 
290   if (IsRef)
291     Roles |= (unsigned)SymbolRole::Reference;
292   else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
293     Roles |= (unsigned)SymbolRole::Definition;
294   else
295     Roles |= (unsigned)SymbolRole::Declaration;
296 
297   D = getCanonicalDecl(D);
298   Parent = adjustParent(Parent);
299   if (Parent)
300     Parent = getCanonicalDecl(Parent);
301 
302   SmallVector<SymbolRelation, 6> FinalRelations;
303   FinalRelations.reserve(Relations.size()+1);
304 
305   auto addRelation = [&](SymbolRelation Rel) {
306     auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
307                 [&](SymbolRelation Elem)->bool {
308                   return Elem.RelatedSymbol == Rel.RelatedSymbol;
309                 });
310     if (It != FinalRelations.end()) {
311       It->Roles |= Rel.Roles;
312     } else {
313       FinalRelations.push_back(Rel);
314     }
315     Roles |= Rel.Roles;
316   };
317 
318   if (Parent) {
319     if (IsRef) {
320       addRelation(SymbolRelation{
321         (unsigned)SymbolRole::RelationContainedBy,
322         Parent
323       });
324     } else if (!cast<DeclContext>(Parent)->isFunctionOrMethod()) {
325       addRelation(SymbolRelation{
326         (unsigned)SymbolRole::RelationChildOf,
327         Parent
328       });
329     }
330   }
331 
332   for (auto &Rel : Relations) {
333     addRelation(SymbolRelation(Rel.Roles,
334                                Rel.RelatedSymbol->getCanonicalDecl()));
335   }
336 
337   IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
338   return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
339                                           Node);
340 }
341