1 //===- IndexingContext.cpp - Indexing context data ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "IndexingContext.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Attr.h"
12 #include "clang/AST/DeclObjC.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Index/IndexDataConsumer.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::shouldIndexParametersInDeclarations() const {
45   return IndexOpts.IndexParametersInDeclarations;
46 }
47 
48 bool IndexingContext::shouldIndexTemplateParameters() const {
49   return IndexOpts.IndexTemplateParameters;
50 }
51 
52 bool IndexingContext::handleDecl(const Decl *D,
53                                  SymbolRoleSet Roles,
54                                  ArrayRef<SymbolRelation> Relations) {
55   return handleDecl(D, D->getLocation(), Roles, Relations);
56 }
57 
58 bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
59                                  SymbolRoleSet Roles,
60                                  ArrayRef<SymbolRelation> Relations,
61                                  const DeclContext *DC) {
62   if (!DC)
63     DC = D->getDeclContext();
64 
65   const Decl *OrigD = D;
66   if (isa<ObjCPropertyImplDecl>(D)) {
67     D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
68   }
69   return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
70                               Roles, Relations,
71                               nullptr, OrigD, DC);
72 }
73 
74 bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
75                                       const NamedDecl *Parent,
76                                       const DeclContext *DC,
77                                       SymbolRoleSet Roles,
78                                       ArrayRef<SymbolRelation> Relations,
79                                       const Expr *RefE,
80                                       const Decl *RefD) {
81   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
82     return true;
83 
84   if (!shouldIndexTemplateParameters() &&
85       (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
86        isa<TemplateTemplateParmDecl>(D))) {
87     return true;
88   }
89   return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations,
90                               RefE, RefD, DC);
91 }
92 
93 static void reportModuleReferences(const Module *Mod,
94                                    ArrayRef<SourceLocation> IdLocs,
95                                    const ImportDecl *ImportD,
96                                    IndexDataConsumer &DataConsumer) {
97   if (!Mod)
98     return;
99   reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
100                          DataConsumer);
101   DataConsumer.handleModuleOccurrence(
102       ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back());
103 }
104 
105 bool IndexingContext::importedModule(const ImportDecl *ImportD) {
106   if (ImportD->isInvalidDecl())
107     return true;
108 
109   SourceLocation Loc;
110   auto IdLocs = ImportD->getIdentifierLocs();
111   if (!IdLocs.empty())
112     Loc = IdLocs.back();
113   else
114     Loc = ImportD->getLocation();
115 
116   SourceManager &SM = Ctx->getSourceManager();
117   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
118   if (FID.isInvalid())
119     return true;
120 
121   bool Invalid = false;
122   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
123   if (Invalid || !SEntry.isFile())
124     return true;
125 
126   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
127     switch (IndexOpts.SystemSymbolFilter) {
128     case IndexingOptions::SystemSymbolFilterKind::None:
129       return true;
130     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
131     case IndexingOptions::SystemSymbolFilterKind::All:
132       break;
133     }
134   }
135 
136   const Module *Mod = ImportD->getImportedModule();
137   if (!ImportD->isImplicit() && Mod->Parent && !IdLocs.empty()) {
138     reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD,
139                            DataConsumer);
140   }
141 
142   SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration;
143   if (ImportD->isImplicit())
144     Roles |= (unsigned)SymbolRole::Implicit;
145 
146   return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc);
147 }
148 
149 bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
150   TemplateSpecializationKind TKind = TSK_Undeclared;
151   if (const ClassTemplateSpecializationDecl *
152       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
153     TKind = SD->getSpecializationKind();
154   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
155     TKind = FD->getTemplateSpecializationKind();
156   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
157     TKind = VD->getTemplateSpecializationKind();
158   } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
159     if (RD->getInstantiatedFromMemberClass())
160       TKind = RD->getTemplateSpecializationKind();
161   } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
162     if (ED->getInstantiatedFromMemberEnum())
163       TKind = ED->getTemplateSpecializationKind();
164   } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
165              isa<EnumConstantDecl>(D)) {
166     if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
167       return isTemplateImplicitInstantiation(Parent);
168   }
169   switch (TKind) {
170     case TSK_Undeclared:
171       // Instantiation maybe not happen yet when we see a SpecializationDecl,
172       // e.g. when the type doesn't need to be complete, we still treat it as an
173       // instantiation as we'd like to keep the canonicalized result consistent.
174       return isa<ClassTemplateSpecializationDecl>(D);
175     case TSK_ExplicitSpecialization:
176       return false;
177     case TSK_ImplicitInstantiation:
178     case TSK_ExplicitInstantiationDeclaration:
179     case TSK_ExplicitInstantiationDefinition:
180       return true;
181   }
182   llvm_unreachable("invalid TemplateSpecializationKind");
183 }
184 
185 bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
186   if (isa<ObjCInterfaceDecl>(D))
187     return false;
188   if (isa<ObjCCategoryDecl>(D))
189     return false;
190   if (isa<ObjCIvarDecl>(D))
191     return false;
192   if (isa<ObjCMethodDecl>(D))
193     return false;
194   if (isa<ImportDecl>(D))
195     return false;
196   return true;
197 }
198 
199 static const CXXRecordDecl *
200 getDeclContextForTemplateInstationPattern(const Decl *D) {
201   if (const auto *CTSD =
202           dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
203     return CTSD->getTemplateInstantiationPattern();
204   else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
205     return RD->getInstantiatedFromMemberClass();
206   return nullptr;
207 }
208 
209 static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
210   if (const ClassTemplateSpecializationDecl *
211       SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
212     const auto *Template = SD->getTemplateInstantiationPattern();
213     if (Template)
214       return Template;
215     // Fallback to primary template if no instantiation is available yet (e.g.
216     // the type doesn't need to be complete).
217     return SD->getSpecializedTemplate()->getTemplatedDecl();
218   } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
219     return FD->getTemplateInstantiationPattern();
220   } else if (auto *VD = dyn_cast<VarDecl>(D)) {
221     return VD->getTemplateInstantiationPattern();
222   } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
223     return RD->getInstantiatedFromMemberClass();
224   } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
225     return ED->getInstantiatedFromMemberEnum();
226   } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
227     const auto *ND = cast<NamedDecl>(D);
228     if (const CXXRecordDecl *Pattern =
229             getDeclContextForTemplateInstationPattern(ND)) {
230       for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
231         if (BaseND->isImplicit())
232           continue;
233         if (BaseND->getKind() == ND->getKind())
234           return BaseND;
235       }
236     }
237   } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
238     if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
239       if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
240         for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
241           return BaseECD;
242       }
243     }
244   }
245   return nullptr;
246 }
247 
248 static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) {
249   if (auto VD = dyn_cast<VarDecl>(D))
250     return VD->isThisDeclarationADefinition(Ctx);
251 
252   if (auto FD = dyn_cast<FunctionDecl>(D))
253     return FD->isThisDeclarationADefinition();
254 
255   if (auto TD = dyn_cast<TagDecl>(D))
256     return TD->isThisDeclarationADefinition();
257 
258   if (auto MD = dyn_cast<ObjCMethodDecl>(D))
259     return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC);
260 
261   if (isa<TypedefNameDecl>(D) || isa<EnumConstantDecl>(D) ||
262       isa<FieldDecl>(D) || isa<MSPropertyDecl>(D) || isa<ObjCImplDecl>(D) ||
263       isa<ObjCPropertyImplDecl>(D) || isa<ConceptDecl>(D))
264     return true;
265 
266   return false;
267 }
268 
269 /// Whether the given NamedDecl should be skipped because it has no name.
270 static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
271   return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
272           !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
273 }
274 
275 static const Decl *adjustParent(const Decl *Parent) {
276   if (!Parent)
277     return nullptr;
278   for (;; Parent = cast<Decl>(Parent->getDeclContext())) {
279     if (isa<TranslationUnitDecl>(Parent))
280       return nullptr;
281     if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent))
282       continue;
283     if (auto NS = dyn_cast<NamespaceDecl>(Parent)) {
284       if (NS->isAnonymousNamespace())
285         continue;
286     } else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
287       if (RD->isAnonymousStructOrUnion())
288         continue;
289     } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
290       if (shouldSkipNamelessDecl(ND))
291         continue;
292     }
293     return Parent;
294   }
295 }
296 
297 static const Decl *getCanonicalDecl(const Decl *D) {
298   D = D->getCanonicalDecl();
299   if (auto TD = dyn_cast<TemplateDecl>(D)) {
300     if (auto TTD = TD->getTemplatedDecl()) {
301       D = TTD;
302       assert(D->isCanonicalDecl());
303     }
304   }
305 
306   return D;
307 }
308 
309 static bool shouldReportOccurrenceForSystemDeclOnlyMode(
310     bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
311   if (!IsRef)
312     return true;
313 
314   auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
315     bool accept = false;
316     applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
317       switch (r) {
318       case SymbolRole::RelationChildOf:
319       case SymbolRole::RelationBaseOf:
320       case SymbolRole::RelationOverrideOf:
321       case SymbolRole::RelationExtendedBy:
322       case SymbolRole::RelationAccessorOf:
323       case SymbolRole::RelationIBTypeOf:
324         accept = true;
325         return false;
326       case SymbolRole::Declaration:
327       case SymbolRole::Definition:
328       case SymbolRole::Reference:
329       case SymbolRole::Read:
330       case SymbolRole::Write:
331       case SymbolRole::Call:
332       case SymbolRole::Dynamic:
333       case SymbolRole::AddressOf:
334       case SymbolRole::Implicit:
335       case SymbolRole::Undefinition:
336       case SymbolRole::RelationReceivedBy:
337       case SymbolRole::RelationCalledBy:
338       case SymbolRole::RelationContainedBy:
339       case SymbolRole::RelationSpecializationOf:
340       case SymbolRole::NameReference:
341         return true;
342       }
343       llvm_unreachable("Unsupported SymbolRole value!");
344     });
345     return accept;
346   };
347 
348   for (auto &Rel : Relations) {
349     if (acceptForRelation(Rel.Roles))
350       return true;
351   }
352 
353   return false;
354 }
355 
356 bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
357                                            bool IsRef, const Decl *Parent,
358                                            SymbolRoleSet Roles,
359                                            ArrayRef<SymbolRelation> Relations,
360                                            const Expr *OrigE,
361                                            const Decl *OrigD,
362                                            const DeclContext *ContainerDC) {
363   if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
364     return true;
365   if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
366     return true;
367 
368   SourceManager &SM = Ctx->getSourceManager();
369   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
370   if (FID.isInvalid())
371     return true;
372 
373   bool Invalid = false;
374   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
375   if (Invalid || !SEntry.isFile())
376     return true;
377 
378   if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
379     switch (IndexOpts.SystemSymbolFilter) {
380     case IndexingOptions::SystemSymbolFilterKind::None:
381       return true;
382     case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
383       if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
384         return true;
385       break;
386     case IndexingOptions::SystemSymbolFilterKind::All:
387       break;
388     }
389   }
390 
391   if (!OrigD)
392     OrigD = D;
393 
394   if (isTemplateImplicitInstantiation(D)) {
395     if (!IsRef)
396       return true;
397     D = adjustTemplateImplicitInstantiation(D);
398     if (!D)
399       return true;
400     assert(!isTemplateImplicitInstantiation(D));
401   }
402 
403   if (IsRef)
404     Roles |= (unsigned)SymbolRole::Reference;
405   else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
406     Roles |= (unsigned)SymbolRole::Definition;
407   else
408     Roles |= (unsigned)SymbolRole::Declaration;
409 
410   D = getCanonicalDecl(D);
411   Parent = adjustParent(Parent);
412   if (Parent)
413     Parent = getCanonicalDecl(Parent);
414 
415   SmallVector<SymbolRelation, 6> FinalRelations;
416   FinalRelations.reserve(Relations.size()+1);
417 
418   auto addRelation = [&](SymbolRelation Rel) {
419     auto It = llvm::find_if(FinalRelations, [&](SymbolRelation Elem) -> bool {
420       return Elem.RelatedSymbol == Rel.RelatedSymbol;
421     });
422     if (It != FinalRelations.end()) {
423       It->Roles |= Rel.Roles;
424     } else {
425       FinalRelations.push_back(Rel);
426     }
427     Roles |= Rel.Roles;
428   };
429 
430   if (Parent) {
431     if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
432       addRelation(SymbolRelation{
433         (unsigned)SymbolRole::RelationContainedBy,
434         Parent
435       });
436     } else {
437       addRelation(SymbolRelation{
438         (unsigned)SymbolRole::RelationChildOf,
439         Parent
440       });
441     }
442   }
443 
444   for (auto &Rel : Relations) {
445     addRelation(SymbolRelation(Rel.Roles,
446                                Rel.RelatedSymbol->getCanonicalDecl()));
447   }
448 
449   IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC};
450   return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node);
451 }
452 
453 void IndexingContext::handleMacroDefined(const IdentifierInfo &Name,
454                                          SourceLocation Loc,
455                                          const MacroInfo &MI) {
456   if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
457     return;
458   SymbolRoleSet Roles = (unsigned)SymbolRole::Definition;
459   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
460 }
461 
462 void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name,
463                                            SourceLocation Loc,
464                                            const MacroInfo &MI) {
465   if (!shouldIndexMacroOccurrence(/*IsRef=*/false, Loc))
466     return;
467   SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition;
468   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
469 }
470 
471 void IndexingContext::handleMacroReference(const IdentifierInfo &Name,
472                                            SourceLocation Loc,
473                                            const MacroInfo &MI) {
474   if (!shouldIndexMacroOccurrence(/*IsRef=*/true, Loc))
475     return;
476   SymbolRoleSet Roles = (unsigned)SymbolRole::Reference;
477   DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc);
478 }
479 
480 bool IndexingContext::shouldIndexMacroOccurrence(bool IsRef,
481                                                  SourceLocation Loc) {
482   if (!IndexOpts.IndexMacros)
483     return false;
484 
485   switch (IndexOpts.SystemSymbolFilter) {
486   case IndexingOptions::SystemSymbolFilterKind::None:
487     break;
488   case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
489     if (!IsRef)
490       return true;
491     break;
492   case IndexingOptions::SystemSymbolFilterKind::All:
493     return true;
494   }
495 
496   SourceManager &SM = Ctx->getSourceManager();
497   FileID FID = SM.getFileID(SM.getFileLoc(Loc));
498   if (FID.isInvalid())
499     return false;
500 
501   bool Invalid = false;
502   const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
503   if (Invalid || !SEntry.isFile())
504     return false;
505 
506   return SEntry.getFile().getFileCharacteristic() == SrcMgr::C_User;
507 }
508