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   } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
128     if (RD->getInstantiatedFromMemberClass())
129       TKind = RD->getTemplateSpecializationKind();
130   } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
131     if (ED->getInstantiatedFromMemberEnum())
132       TKind = ED->getTemplateSpecializationKind();
133   } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
134              isa<EnumConstantDecl>(D)) {
135     if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
136       return isTemplateImplicitInstantiation(Parent);
137   }
138   switch (TKind) {
139     case TSK_Undeclared:
140     case TSK_ExplicitSpecialization:
141       return false;
142     case TSK_ImplicitInstantiation:
143     case TSK_ExplicitInstantiationDeclaration:
144     case TSK_ExplicitInstantiationDefinition:
145       return true;
146   }
147   llvm_unreachable("invalid TemplateSpecializationKind");
148 }
149 
150 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
151   if (isa<ObjCInterfaceDecl>(D))
152     return false;
153   if (isa<ObjCCategoryDecl>(D))
154     return false;
155   if (isa<ObjCIvarDecl>(D))
156     return false;
157   if (isa<ObjCMethodDecl>(D))
158     return false;
159   if (isa<ImportDecl>(D))
160     return false;
161   return true;
162 }
163 
164 static const CXXRecordDecl *
165 getDeclContextForTemplateInstationPattern(const Decl *D) {
166   if (const auto *CTSD =
167           dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
168     return CTSD->getTemplateInstantiationPattern();
169   else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
170     return RD->getInstantiatedFromMemberClass();
171   return nullptr;
172 }
173 
174 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
175   if (const ClassTemplateSpecializationDecl *
176       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
177     return SD->getTemplateInstantiationPattern();
178   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
179     return FD->getTemplateInstantiationPattern();
180   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
181     return VD->getTemplateInstantiationPattern();
182   } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
183     return RD->getInstantiatedFromMemberClass();
184   } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
185     return ED->getInstantiatedFromMemberEnum();
186   } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
187     const auto *ND = cast<NamedDecl>(D);
188     if (const CXXRecordDecl *Pattern =
189             getDeclContextForTemplateInstationPattern(ND)) {
190       for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
191         if (BaseND->isImplicit())
192           continue;
193         if (BaseND->getKind() == ND->getKind())
194           return BaseND;
195       }
196     }
197   } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
198     if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
199       if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
200         for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
201           return BaseECD;
202       }
203     }
204   }
205   return nullptr;
206 }
207 
208 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
209   if (auto VD = dyn_cast<VarDecl>(D))
210     return VD->isThisDeclarationADefinition(Ctx);
211 
212   if (auto FD = dyn_cast<FunctionDecl>(D))
213     return FD->isThisDeclarationADefinition();
214 
215   if (auto TD = dyn_cast<TagDecl>(D))
216     return TD->isThisDeclarationADefinition();
217 
218   if (auto MD = dyn_cast<ObjCMethodDecl>(D))
219     return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
220 
221   if (isa<TypedefNameDecl>(D) ||
222       isa<EnumConstantDecl>(D) ||
223       isa<FieldDecl>(D) ||
224       isa<MSPropertyDecl>(D) ||
225       isa<ObjCImplDecl>(D) ||
226       isa<ObjCPropertyImplDecl>(D))
227     return true;
228 
229   return false;
230 }
231 
232 /// Whether the given NamedDecl should be skipped because it has no name.
233 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
234   return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
235           !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
236 }
237 
238 static const Decl *adjustParent(const Decl *Parent) {
239   if (!Parent)
240     return nullptr;
241   for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
242     if (isa<TranslationUnitDecl>(Parent))
243       return nullptr;
244     if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
245       continue;
246     if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
247       if (NS->isAnonymousNamespace())
248         continue;
249     } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
250       if (RD->isAnonymousStructOrUnion())
251         continue;
252     } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
253       if (shouldSkipNamelessDecl(ND))
254         continue;
255     }
256     return Parent;
257   }
258 }
259 
260 static const Decl *getCanonicalDecl(const Decl *D) {
261   D = D->getCanonicalDecl();
262   if (auto TD = dyn_cast<TemplateDecl>(D)) {
263     if (auto TTD = TD->getTemplatedDecl()) {
264       D = TTD;
265       assert(D->isCanonicalDecl());
266     }
267   }
268 
269   return D;
270 }
271 
272 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
273     bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
274   if (!IsRef)
275     return true;
276 
277   auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
278     bool accept = false;
279     applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
280       switch (r) {
281       case SymbolRole::RelationChildOf:
282       case SymbolRole::RelationBaseOf:
283       case SymbolRole::RelationOverrideOf:
284       case SymbolRole::RelationExtendedBy:
285       case SymbolRole::RelationAccessorOf:
286       case SymbolRole::RelationIBTypeOf:
287         accept = true;
288         return false;
289       case SymbolRole::Declaration:
290       case SymbolRole::Definition:
291       case SymbolRole::Reference:
292       case SymbolRole::Read:
293       case SymbolRole::Write:
294       case SymbolRole::Call:
295       case SymbolRole::Dynamic:
296       case SymbolRole::AddressOf:
297       case SymbolRole::Implicit:
298       case SymbolRole::RelationReceivedBy:
299       case SymbolRole::RelationCalledBy:
300       case SymbolRole::RelationContainedBy:
301       case SymbolRole::RelationSpecializationOf:
302         return true;
303       }
304       llvm_unreachable("Unsupported SymbolRole value!");
305     });
306     return accept;
307   };
308 
309   for (auto &Rel : Relations) {
310     if (acceptForRelation(Rel.Roles))
311       return true;
312   }
313 
314   return false;
315 }
316 
317 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
318                                            bool IsRef, const Decl *Parent,
319                                            SymbolRoleSet Roles,
320                                            ArrayRef<SymbolRelation> Relations,
321                                            const Expr *OrigE,
322                                            const Decl *OrigD,
323                                            const DeclContext *ContainerDC) {
324   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
325     return true;
326   if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
327     return true;
328 
329   SourceManager &SM = Ctx->getSourceManager();
330   Loc = SM.getFileLoc(Loc);
331   if (Loc.isInvalid())
332     return true;
333 
334   FileID FID;
335   unsigned Offset;
336   std::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
337   if (FID.isInvalid())
338     return true;
339 
340   bool Invalid = false;
341   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
342   if (Invalid || !SEntry.isFile())
343     return true;
344 
345   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
346     switch (IndexOpts.SystemSymbolFilter) {
347     case IndexingOptions::SystemSymbolFilterKind::None:
348       return true;
349     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
350       if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
351         return true;
352       break;
353     case IndexingOptions::SystemSymbolFilterKind::All:
354       break;
355     }
356   }
357 
358   if (isTemplateImplicitInstantiation(D)) {
359     if (!IsRef)
360       return true;
361     D = adjustTemplateImplicitInstantiation(D);
362     if (!D)
363       return true;
364     assert(!isTemplateImplicitInstantiation(D));
365   }
366 
367   if (!OrigD)
368     OrigD = D;
369 
370   if (IsRef)
371     Roles |= (unsigned)SymbolRole::Reference;
372   else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
373     Roles |= (unsigned)SymbolRole::Definition;
374   else
375     Roles |= (unsigned)SymbolRole::Declaration;
376 
377   D = getCanonicalDecl(D);
378   Parent = adjustParent(Parent);
379   if (Parent)
380     Parent = getCanonicalDecl(Parent);
381 
382   SmallVector<SymbolRelation, 6> FinalRelations;
383   FinalRelations.reserve(Relations.size()+1);
384 
385   auto addRelation = [&](SymbolRelation Rel) {
386     auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
387                 [&](SymbolRelation Elem)->bool {
388                   return Elem.RelatedSymbol == Rel.RelatedSymbol;
389                 });
390     if (It != FinalRelations.end()) {
391       It->Roles |= Rel.Roles;
392     } else {
393       FinalRelations.push_back(Rel);
394     }
395     Roles |= Rel.Roles;
396   };
397 
398   if (Parent) {
399     if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
400       addRelation(SymbolRelation{
401         (unsigned)SymbolRole::RelationContainedBy,
402         Parent
403       });
404     } else {
405       addRelation(SymbolRelation{
406         (unsigned)SymbolRole::RelationChildOf,
407         Parent
408       });
409     }
410   }
411 
412   for (auto &Rel : Relations) {
413     addRelation(SymbolRelation(Rel.Roles,
414                                Rel.RelatedSymbol->getCanonicalDecl()));
415   }
416 
417   IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC };
418   return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset,
419                                           Node);
420 }
421