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/Basic/SourceLocation.h"
12 #include "clang/Index/IndexDataConsumer.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/AST/DeclObjC.h"
16 #include "clang/Basic/SourceManager.h"
17 
18 using namespace clang;
19 using namespace index;
20 
21 static bool isGeneratedDecl(const Decl *D) {
22   if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
23     return attr->getGeneratedDeclaration();
24   }
25   return false;
26 }
27 
28 bool IndexingContext::shouldIndex(const Decl *D) {
29   return !isGeneratedDecl(D);
30 }
31 
32 const LangOptions &IndexingContext::getLangOpts() const {
33   return Ctx->getLangOpts();
34 }
35 
36 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
37   return IndexOpts.IndexFunctionLocals;
38 }
39 
40 bool IndexingContext::shouldIndexImplicitInstantiation() const {
41   return IndexOpts.IndexImplicitInstantiation;
42 }
43 
44 bool IndexingContext::handleDecl(const Decl *D,
45                                  SymbolRoleSet Roles,
46                                  ArrayRef<SymbolRelation> Relations) {
47   return handleDecl(D, D->getLocation(), Roles, Relations);
48 }
49 
50 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
51                                  SymbolRoleSet Roles,
52                                  ArrayRef<SymbolRelation> Relations,
53                                  const DeclContext *DC) {
54   if (!DC)
55     DC = D->getDeclContext();
56 
57   const Decl *OrigD = D;
58   if (isa<ObjCPropertyImplDecl>(D)) {
59     D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
60   }
61   return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
62                               Roles, Relations,
63                               nullptr, OrigD, DC);
64 }
65 
66 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
67                                       const NamedDecl *Parent,
68                                       const DeclContext *DC,
69                                       SymbolRoleSet Roles,
70                                       ArrayRef<SymbolRelation> Relations,
71                                       const Expr *RefE,
72                                       const Decl *RefD) {
73   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
74     return true;
75 
76   if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
77     return true;
78 
79   return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
80                               RefE, RefD, DC);
81 }
82 
83 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
84   SourceLocation Loc;
85   auto IdLocs = ImportD->getIdentifierLocs();
86   if (!IdLocs.empty())
87     Loc = IdLocs.front();
88   else
89     Loc = ImportD->getLocation();
90 
91   SourceManager &SM = Ctx->getSourceManager();
92   FileID FID = SM.getFileID(SM.getFileLoc(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, Loc);
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::Undefinition:
299       case SymbolRole::RelationReceivedBy:
300       case SymbolRole::RelationCalledBy:
301       case SymbolRole::RelationContainedBy:
302       case SymbolRole::RelationSpecializationOf:
303         return true;
304       }
305       llvm_unreachable("Unsupported SymbolRole value!");
306     });
307     return accept;
308   };
309 
310   for (auto &Rel : Relations) {
311     if (acceptForRelation(Rel.Roles))
312       return true;
313   }
314 
315   return false;
316 }
317 
318 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
319                                            bool IsRef, const Decl *Parent,
320                                            SymbolRoleSet Roles,
321                                            ArrayRef<SymbolRelation> Relations,
322                                            const Expr *OrigE,
323                                            const Decl *OrigD,
324                                            const DeclContext *ContainerDC) {
325   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
326     return true;
327   if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
328     return true;
329 
330   SourceManager &SM = Ctx->getSourceManager();
331   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
332   if (FID.isInvalid())
333     return true;
334 
335   bool Invalid = false;
336   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
337   if (Invalid || !SEntry.isFile())
338     return true;
339 
340   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
341     switch (IndexOpts.SystemSymbolFilter) {
342     case IndexingOptions::SystemSymbolFilterKind::None:
343       return true;
344     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
345       if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
346         return true;
347       break;
348     case IndexingOptions::SystemSymbolFilterKind::All:
349       break;
350     }
351   }
352 
353   if (!OrigD)
354     OrigD = D;
355 
356   if (isTemplateImplicitInstantiation(D)) {
357     if (!IsRef)
358       return true;
359     D = adjustTemplateImplicitInstantiation(D);
360     if (!D)
361       return true;
362     assert(!isTemplateImplicitInstantiation(D));
363   }
364 
365   if (IsRef)
366     Roles |= (unsigned)SymbolRole::Reference;
367   else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
368     Roles |= (unsigned)SymbolRole::Definition;
369   else
370     Roles |= (unsigned)SymbolRole::Declaration;
371 
372   D = getCanonicalDecl(D);
373   Parent = adjustParent(Parent);
374   if (Parent)
375     Parent = getCanonicalDecl(Parent);
376 
377   SmallVector<SymbolRelation, 6> FinalRelations;
378   FinalRelations.reserve(Relations.size()+1);
379 
380   auto addRelation = [&](SymbolRelation Rel) {
381     auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(),
382                 [&](SymbolRelation Elem)->bool {
383                   return Elem.RelatedSymbol == Rel.RelatedSymbol;
384                 });
385     if (It != FinalRelations.end()) {
386       It->Roles |= Rel.Roles;
387     } else {
388       FinalRelations.push_back(Rel);
389     }
390     Roles |= Rel.Roles;
391   };
392 
393   if (Parent) {
394     if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
395       addRelation(SymbolRelation{
396         (unsigned)SymbolRole::RelationContainedBy,
397         Parent
398       });
399     } else {
400       addRelation(SymbolRelation{
401         (unsigned)SymbolRole::RelationChildOf,
402         Parent
403       });
404     }
405   }
406 
407   for (auto &Rel : Relations) {
408     addRelation(SymbolRelation(Rel.Roles,
409                                Rel.RelatedSymbol->getCanonicalDecl()));
410   }
411 
412   IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
413   return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node);
414 }
415 
416 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
417                                          SourceLocation Loc,
418                                          const MacroInfo &MI) {
419   SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
420   DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
421 }
422 
423 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
424                                            SourceLocation Loc,
425                                            const MacroInfo &MI) {
426   SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
427   DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
428 }
429 
430 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
431                                            SourceLocation Loc,
432                                            const MacroInfo &MI) {
433   SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
434   DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc);
435 }
436