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