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