1 //===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===//
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/RecursiveASTVisitor.h"
11 
12 using namespace clang;
13 using namespace index;
14 
15 namespace {
16 
17 class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
18   IndexingContext &IndexCtx;
19   const NamedDecl *Parent;
20   const DeclContext *ParentDC;
21   bool IsBase;
22   SmallVector<SymbolRelation, 3> Relations;
23 
24   typedef RecursiveASTVisitor<TypeIndexer> base;
25 
26 public:
27   TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent,
28               const DeclContext *DC, bool isBase, bool isIBType)
29     : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) {
30     if (IsBase) {
31       assert(Parent);
32       Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent);
33     }
34     if (isIBType) {
35       assert(Parent);
36       Relations.emplace_back((unsigned)SymbolRole::RelationIBTypeOf, Parent);
37     }
38   }
39 
40   bool shouldWalkTypesOfTypeLocs() const { return false; }
41 
42 #define TRY_TO(CALL_EXPR)                                                      \
43   do {                                                                         \
44     if (!CALL_EXPR)                                                            \
45       return false;                                                            \
46   } while (0)
47 
48   bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
49     SourceLocation Loc = TL.getNameLoc();
50     TypedefNameDecl *ND = TL.getTypedefNameDecl();
51     if (ND->isTransparentTag()) {
52       TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl();
53       return IndexCtx.handleReference(Underlying, Loc, Parent,
54                                       ParentDC, SymbolRoleSet(), Relations);
55     }
56     if (IsBase) {
57       TRY_TO(IndexCtx.handleReference(ND, Loc,
58                                       Parent, ParentDC, SymbolRoleSet()));
59       if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
60         TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
61                                         (unsigned)SymbolRole::Implicit,
62                                         Relations));
63       }
64     } else {
65       TRY_TO(IndexCtx.handleReference(ND, Loc,
66                                       Parent, ParentDC, SymbolRoleSet(),
67                                       Relations));
68     }
69     return true;
70   }
71 
72   bool traverseParamVarHelper(ParmVarDecl *D) {
73     TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
74     if (D->getTypeSourceInfo())
75       TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
76     return true;
77   }
78 
79   bool TraverseParmVarDecl(ParmVarDecl *D) {
80     // Avoid visiting default arguments from the definition that were already
81     // visited in the declaration.
82     // FIXME: A free function definition can have default arguments.
83     // Avoiding double visitaiton of default arguments should be handled by the
84     // visitor probably with a bit in the AST to indicate if the attached
85     // default argument was 'inherited' or written in source.
86     if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) {
87       if (FD->isThisDeclarationADefinition()) {
88         return traverseParamVarHelper(D);
89       }
90     }
91 
92     return base::TraverseParmVarDecl(D);
93   }
94 
95   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
96     IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
97     return true;
98   }
99 
100   bool VisitTagTypeLoc(TagTypeLoc TL) {
101     TagDecl *D = TL.getDecl();
102     if (!IndexCtx.shouldIndexFunctionLocalSymbols() &&
103         D->getParentFunctionOrMethod())
104       return true;
105 
106     if (TL.isDefinition()) {
107       IndexCtx.indexTagDecl(D);
108       return true;
109     }
110 
111     return IndexCtx.handleReference(D, TL.getNameLoc(),
112                                     Parent, ParentDC, SymbolRoleSet(),
113                                     Relations);
114   }
115 
116   bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
117     return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
118                                     Parent, ParentDC, SymbolRoleSet(), Relations);
119   }
120 
121   bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
122     for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
123       IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
124                                Parent, ParentDC, SymbolRoleSet(), Relations);
125     }
126     return true;
127   }
128 
129   template<typename TypeLocType>
130   bool HandleTemplateSpecializationTypeLoc(TypeLocType TL) {
131     if (const auto *T = TL.getTypePtr()) {
132       if (IndexCtx.shouldIndexImplicitInstantiation()) {
133         if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
134           IndexCtx.handleReference(RD, TL.getTemplateNameLoc(),
135                                    Parent, ParentDC, SymbolRoleSet(), Relations);
136           return true;
137         }
138       }
139       if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl())
140         IndexCtx.handleReference(D, TL.getTemplateNameLoc(), Parent, ParentDC,
141                                  SymbolRoleSet(), Relations);
142     }
143     return true;
144   }
145 
146   bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
147     return HandleTemplateSpecializationTypeLoc(TL);
148   }
149 
150   bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) {
151     return HandleTemplateSpecializationTypeLoc(TL);
152   }
153 
154   bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
155     const DependentNameType *DNT = TL.getTypePtr();
156     const NestedNameSpecifier *NNS = DNT->getQualifier();
157     const Type *T = NNS->getAsType();
158     if (!T)
159       return true;
160     const TemplateSpecializationType *TST =
161         T->getAs<TemplateSpecializationType>();
162     if (!TST)
163       return true;
164     TemplateName TN = TST->getTemplateName();
165     const ClassTemplateDecl *TD =
166         dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
167     if (!TD)
168       return true;
169     CXXRecordDecl *RD = TD->getTemplatedDecl();
170     if (!RD->hasDefinition())
171       return true;
172     RD = RD->getDefinition();
173     DeclarationName Name(DNT->getIdentifier());
174     std::vector<const NamedDecl *> Symbols = RD->lookupDependentName(
175         Name, [](const NamedDecl *ND) { return isa<TypeDecl>(ND); });
176     if (Symbols.size() != 1)
177       return true;
178     return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
179                                     ParentDC, SymbolRoleSet(), Relations);
180   }
181 
182   bool TraverseStmt(Stmt *S) {
183     IndexCtx.indexBody(S, Parent, ParentDC);
184     return true;
185   }
186 };
187 
188 } // anonymous namespace
189 
190 void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
191                                           const NamedDecl *Parent,
192                                           const DeclContext *DC,
193                                           bool isBase,
194                                           bool isIBType) {
195   if (!TInfo || TInfo->getTypeLoc().isNull())
196     return;
197 
198   indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase, isIBType);
199 }
200 
201 void IndexingContext::indexTypeLoc(TypeLoc TL,
202                                    const NamedDecl *Parent,
203                                    const DeclContext *DC,
204                                    bool isBase,
205                                    bool isIBType) {
206   if (TL.isNull())
207     return;
208 
209   if (!DC)
210     DC = Parent->getLexicalDeclContext();
211   TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL);
212 }
213 
214 void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
215                                                   const NamedDecl *Parent,
216                                                   const DeclContext *DC) {
217   if (!NNS)
218     return;
219 
220   if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
221     indexNestedNameSpecifierLoc(Prefix, Parent, DC);
222 
223   if (!DC)
224     DC = Parent->getLexicalDeclContext();
225   SourceLocation Loc = NNS.getLocalBeginLoc();
226 
227   switch (NNS.getNestedNameSpecifier()->getKind()) {
228   case NestedNameSpecifier::Identifier:
229   case NestedNameSpecifier::Global:
230   case NestedNameSpecifier::Super:
231     break;
232 
233   case NestedNameSpecifier::Namespace:
234     handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
235                     Loc, Parent, DC, SymbolRoleSet());
236     break;
237   case NestedNameSpecifier::NamespaceAlias:
238     handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
239                     Loc, Parent, DC, SymbolRoleSet());
240     break;
241 
242   case NestedNameSpecifier::TypeSpec:
243   case NestedNameSpecifier::TypeSpecWithTemplate:
244     indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
245     break;
246   }
247 }
248 
249 void IndexingContext::indexTagDecl(const TagDecl *D,
250                                    ArrayRef<SymbolRelation> Relations) {
251   if (!shouldIndex(D))
252     return;
253   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
254     return;
255 
256   if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
257     if (D->isThisDeclarationADefinition()) {
258       indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
259       if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
260         for (const auto &I : CXXRD->bases()) {
261           indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true);
262         }
263       }
264       indexDeclContext(D);
265     }
266   }
267 }
268