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 VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL) {
49     SourceLocation Loc = TTPL.getNameLoc();
50     TemplateTypeParmDecl *TTPD = TTPL.getDecl();
51     return IndexCtx.handleReference(TTPD, Loc, Parent, ParentDC,
52                                     SymbolRoleSet());
53   }
54 
55   bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
56     SourceLocation Loc = TL.getNameLoc();
57     TypedefNameDecl *ND = TL.getTypedefNameDecl();
58     if (ND->isTransparentTag()) {
59       TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl();
60       return IndexCtx.handleReference(Underlying, Loc, Parent,
61                                       ParentDC, SymbolRoleSet(), Relations);
62     }
63     if (IsBase) {
64       TRY_TO(IndexCtx.handleReference(ND, Loc,
65                                       Parent, ParentDC, SymbolRoleSet()));
66       if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
67         TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
68                                         (unsigned)SymbolRole::Implicit,
69                                         Relations));
70       }
71     } else {
72       TRY_TO(IndexCtx.handleReference(ND, Loc,
73                                       Parent, ParentDC, SymbolRoleSet(),
74                                       Relations));
75     }
76     return true;
77   }
78 
79   bool traverseParamVarHelper(ParmVarDecl *D) {
80     TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
81     if (D->getTypeSourceInfo())
82       TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
83     return true;
84   }
85 
86   bool TraverseParmVarDecl(ParmVarDecl *D) {
87     // Avoid visiting default arguments from the definition that were already
88     // visited in the declaration.
89     // FIXME: A free function definition can have default arguments.
90     // Avoiding double visitaiton of default arguments should be handled by the
91     // visitor probably with a bit in the AST to indicate if the attached
92     // default argument was 'inherited' or written in source.
93     if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) {
94       if (FD->isThisDeclarationADefinition()) {
95         return traverseParamVarHelper(D);
96       }
97     }
98 
99     return base::TraverseParmVarDecl(D);
100   }
101 
102   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
103     IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
104     return true;
105   }
106 
107   bool VisitTagTypeLoc(TagTypeLoc TL) {
108     TagDecl *D = TL.getDecl();
109     if (!IndexCtx.shouldIndexFunctionLocalSymbols() &&
110         D->getParentFunctionOrMethod())
111       return true;
112 
113     if (TL.isDefinition()) {
114       IndexCtx.indexTagDecl(D);
115       return true;
116     }
117 
118     return IndexCtx.handleReference(D, TL.getNameLoc(),
119                                     Parent, ParentDC, SymbolRoleSet(),
120                                     Relations);
121   }
122 
123   bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
124     return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
125                                     Parent, ParentDC, SymbolRoleSet(), Relations);
126   }
127 
128   bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
129     for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
130       IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
131                                Parent, ParentDC, SymbolRoleSet(), Relations);
132     }
133     return true;
134   }
135 
136   void HandleTemplateSpecializationTypeLoc(TemplateName TemplName,
137                                            SourceLocation TemplNameLoc,
138                                            CXXRecordDecl *ResolvedClass,
139                                            bool IsTypeAlias) {
140     // In presence of type aliases, the resolved class was never written in
141     // the code so don't report it.
142     if (!IsTypeAlias && ResolvedClass &&
143         (!ResolvedClass->isImplicit() ||
144          IndexCtx.shouldIndexImplicitInstantiation())) {
145       IndexCtx.handleReference(ResolvedClass, TemplNameLoc, Parent, ParentDC,
146                                SymbolRoleSet(), Relations);
147     } else if (const TemplateDecl *D = TemplName.getAsTemplateDecl()) {
148       IndexCtx.handleReference(D, TemplNameLoc, Parent, ParentDC,
149                                SymbolRoleSet(), Relations);
150     }
151   }
152 
153   bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
154     auto *T = TL.getTypePtr();
155     if (!T)
156       return true;
157     HandleTemplateSpecializationTypeLoc(
158         T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),
159         T->isTypeAlias());
160     return true;
161   }
162 
163   bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) {
164     auto *T = TL.getTypePtr();
165     if (!T)
166       return true;
167     HandleTemplateSpecializationTypeLoc(
168         T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),
169         /*IsTypeAlias=*/false);
170     return true;
171   }
172 
173   bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
174     return IndexCtx.handleReference(TL.getDecl(), TL.getNameLoc(), Parent,
175                                     ParentDC, SymbolRoleSet(), Relations);
176   }
177 
178   bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
179     const DependentNameType *DNT = TL.getTypePtr();
180     const NestedNameSpecifier *NNS = DNT->getQualifier();
181     const Type *T = NNS->getAsType();
182     if (!T)
183       return true;
184     const TemplateSpecializationType *TST =
185         T->getAs<TemplateSpecializationType>();
186     if (!TST)
187       return true;
188     TemplateName TN = TST->getTemplateName();
189     const ClassTemplateDecl *TD =
190         dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
191     if (!TD)
192       return true;
193     CXXRecordDecl *RD = TD->getTemplatedDecl();
194     if (!RD->hasDefinition())
195       return true;
196     RD = RD->getDefinition();
197     DeclarationName Name(DNT->getIdentifier());
198     std::vector<const NamedDecl *> Symbols = RD->lookupDependentName(
199         Name, [](const NamedDecl *ND) { return isa<TypeDecl>(ND); });
200     if (Symbols.size() != 1)
201       return true;
202     return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
203                                     ParentDC, SymbolRoleSet(), Relations);
204   }
205 
206   bool TraverseStmt(Stmt *S) {
207     IndexCtx.indexBody(S, Parent, ParentDC);
208     return true;
209   }
210 };
211 
212 } // anonymous namespace
213 
214 void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
215                                           const NamedDecl *Parent,
216                                           const DeclContext *DC,
217                                           bool isBase,
218                                           bool isIBType) {
219   if (!TInfo || TInfo->getTypeLoc().isNull())
220     return;
221 
222   indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase, isIBType);
223 }
224 
225 void IndexingContext::indexTypeLoc(TypeLoc TL,
226                                    const NamedDecl *Parent,
227                                    const DeclContext *DC,
228                                    bool isBase,
229                                    bool isIBType) {
230   if (TL.isNull())
231     return;
232 
233   if (!DC)
234     DC = Parent->getLexicalDeclContext();
235   TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL);
236 }
237 
238 void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
239                                                   const NamedDecl *Parent,
240                                                   const DeclContext *DC) {
241   if (!NNS)
242     return;
243 
244   if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
245     indexNestedNameSpecifierLoc(Prefix, Parent, DC);
246 
247   if (!DC)
248     DC = Parent->getLexicalDeclContext();
249   SourceLocation Loc = NNS.getLocalBeginLoc();
250 
251   switch (NNS.getNestedNameSpecifier()->getKind()) {
252   case NestedNameSpecifier::Identifier:
253   case NestedNameSpecifier::Global:
254   case NestedNameSpecifier::Super:
255     break;
256 
257   case NestedNameSpecifier::Namespace:
258     handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
259                     Loc, Parent, DC, SymbolRoleSet());
260     break;
261   case NestedNameSpecifier::NamespaceAlias:
262     handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
263                     Loc, Parent, DC, SymbolRoleSet());
264     break;
265 
266   case NestedNameSpecifier::TypeSpec:
267   case NestedNameSpecifier::TypeSpecWithTemplate:
268     indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
269     break;
270   }
271 }
272 
273 void IndexingContext::indexTagDecl(const TagDecl *D,
274                                    ArrayRef<SymbolRelation> Relations) {
275   if (!shouldIndex(D))
276     return;
277   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
278     return;
279 
280   if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
281     if (D->isThisDeclarationADefinition()) {
282       indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
283       if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
284         for (const auto &I : CXXRD->bases()) {
285           indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true);
286         }
287       }
288       indexDeclContext(D);
289     }
290   }
291 }
292