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   SourceManager &SM = Ctx->getSourceManager();
86   Loc = SM.getFileLoc(Loc);
87   if (Loc.isInvalid())
88     return true;
89 
90   FileID FID;
91   unsigned Offset;
92   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
93   if (FID.isInvalid())
94     return true;
95 
96   bool Invalid = false;
97   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
98   if (Invalid || !SEntry.isFile())
99     return true;
100 
101   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
102     switch (IndexOpts.SystemSymbolFilter) {
103     case IndexingOptions::SystemSymbolFilterKind::None:
104       return true;
105     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
106     case IndexingOptions::SystemSymbolFilterKind::All:
107       break;
108     }
109   }
110 
111   SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
112   if (ImportD->isImplicit())
113     Roles |= (unsigned)SymbolRole::Implicit;
114 
115   return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
116 }
117 
118 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
119   TemplateSpecializationKind TKind = TSK_Undeclared;
120   if (const ClassTemplateSpecializationDecl *
121       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
122     TKind = SD->getSpecializationKind();
123   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
124     TKind = FD->getTemplateSpecializationKind();
125   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
126     TKind = VD->getTemplateSpecializationKind();
127   }
128   switch (TKind) {
129     case TSK_Undeclared:
130     case TSK_ExplicitSpecialization:
131       return false;
132     case TSK_ImplicitInstantiation:
133     case TSK_ExplicitInstantiationDeclaration:
134     case TSK_ExplicitInstantiationDefinition:
135       return true;
136   }
137   llvm_unreachable("invalid TemplateSpecializationKind");
138 }
139 
140 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
141   if (isa<ObjCInterfaceDecl>(D))
142     return false;
143   if (isa<ObjCCategoryDecl>(D))
144     return false;
145   if (isa<ObjCIvarDecl>(D))
146     return false;
147   if (isa<ObjCMethodDecl>(D))
148     return false;
149   if (isa<ImportDecl>(D))
150     return false;
151   return true;
152 }
153 
154 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
155   if (const ClassTemplateSpecializationDecl *
156       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
157     return SD->getTemplateInstantiationPattern();
158   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
159     return FD->getTemplateInstantiationPattern();
160   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
161     return VD->getTemplateInstantiationPattern();
162   }
163   return nullptr;
164 }
165 
166 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, 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() || isa<ObjCImplDecl>(ContainerDC);
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 RD = dyn_cast<RecordDecl>(Parent)) {
202       if (RD->isAnonymousStructOrUnion())
203         continue;
204     } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
205       if (FD->getDeclName().isEmpty())
206         continue;
207     }
208     return Parent;
209   }
210 }
211 
212 static const Decl *getCanonicalDecl(const Decl *D) {
213   D = D->getCanonicalDecl();
214   if (auto TD = dyn_cast<TemplateDecl>(D)) {
215     D = TD->getTemplatedDecl();
216     assert(D->isCanonicalDecl());
217   }
218 
219   return D;
220 }
221 
222 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
223     bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
224   if (!IsRef)
225     return true;
226 
227   auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
228     bool accept = false;
229     applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
230       switch (r) {
231       case SymbolRole::RelationChildOf:
232       case SymbolRole::RelationBaseOf:
233       case SymbolRole::RelationOverrideOf:
234       case SymbolRole::RelationExtendedBy:
235       case SymbolRole::RelationAccessorOf:
236       case SymbolRole::RelationIBTypeOf:
237         accept = true;
238         return false;
239       case SymbolRole::Declaration:
240       case SymbolRole::Definition:
241       case SymbolRole::Reference:
242       case SymbolRole::Read:
243       case SymbolRole::Write:
244       case SymbolRole::Call:
245       case SymbolRole::Dynamic:
246       case SymbolRole::AddressOf:
247       case SymbolRole::Implicit:
248       case SymbolRole::RelationReceivedBy:
249       case SymbolRole::RelationCalledBy:
250       case SymbolRole::RelationContainedBy:
251       case SymbolRole::RelationSpecializationOf:
252         return true;
253       }
254       llvm_unreachable("Unsupported SymbolRole value!");
255     });
256     return accept;
257   };
258 
259   for (auto &Rel : Relations) {
260     if (acceptForRelation(Rel.Roles))
261       return true;
262   }
263 
264   return false;
265 }
266 
267 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
268                                            bool IsRef, const Decl *Parent,
269                                            SymbolRoleSet Roles,
270                                            ArrayRef<SymbolRelation> Relations,
271                                            const Expr *OrigE,
272                                            const Decl *OrigD,
273                                            const DeclContext *ContainerDC) {
274   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
275     return true;
276   if (!isa<NamedDecl>(D) ||
277       (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
278        !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
279     return true;
280 
281   SourceManager &SM = Ctx->getSourceManager();
282   Loc = SM.getFileLoc(Loc);
283   if (Loc.isInvalid())
284     return true;
285 
286   FileID FID;
287   unsigned Offset;
288   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
289   if (FID.isInvalid())
290     return true;
291 
292   bool Invalid = false;
293   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
294   if (Invalid || !SEntry.isFile())
295     return true;
296 
297   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
298     switch (IndexOpts.SystemSymbolFilter) {
299     case IndexingOptions::SystemSymbolFilterKind::None:
300       return true;
301     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
302       if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
303         return true;
304       break;
305     case IndexingOptions::SystemSymbolFilterKind::All:
306       break;
307     }
308   }
309 
310   if (isTemplateImplicitInstantiation(D)) {
311     if (!IsRef)
312       return true;
313     D = adjustTemplateImplicitInstantiation(D);
314     if (!D)
315       return true;
316     assert(!isTemplateImplicitInstantiation(D));
317   }
318 
319   if (!OrigD)
320     OrigD = D;
321 
322   if (IsRef)
323     Roles |= (unsigned)SymbolRole::Reference;
324   else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
325     Roles |= (unsigned)SymbolRole::Definition;
326   else
327     Roles |= (unsigned)SymbolRole::Declaration;
328 
329   D = getCanonicalDecl(D);
330   Parent = adjustParent(Parent);
331   if (Parent)
332     Parent = getCanonicalDecl(Parent);
333 
334   SmallVector<SymbolRelation, 6> FinalRelations;
335   FinalRelations.reserve(Relations.size()+1);
336 
337   auto addRelation = [&](SymbolRelation Rel) {
338     auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
339                 [&](SymbolRelation Elem)->bool {
340                   return Elem.RelatedSymbol == Rel.RelatedSymbol;
341                 });
342     if (It != FinalRelations.end()) {
343       It->Roles |= Rel.Roles;
344     } else {
345       FinalRelations.push_back(Rel);
346     }
347     Roles |= Rel.Roles;
348   };
349 
350   if (Parent) {
351     if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
352       addRelation(SymbolRelation{
353         (unsigned)SymbolRole::RelationContainedBy,
354         Parent
355       });
356     } else {
357       addRelation(SymbolRelation{
358         (unsigned)SymbolRole::RelationChildOf,
359         Parent
360       });
361     }
362   }
363 
364   for (auto &Rel : Relations) {
365     addRelation(SymbolRelation(Rel.Roles,
366                                Rel.RelatedSymbol->getCanonicalDecl()));
367   }
368 
369   IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
370   return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
371                                           Node);
372 }
373