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