xref: /freebsd/contrib/llvm-project/clang/lib/Index/IndexTypeSourceInfo.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/ASTConcept.h"
11 #include "clang/AST/PrettyPrinter.h"
12 #include "clang/AST/RecursiveASTVisitor.h"
13 #include "clang/AST/TypeLoc.h"
14 #include "clang/Sema/HeuristicResolver.h"
15 #include "llvm/ADT/ScopeExit.h"
16 
17 using namespace clang;
18 using namespace index;
19 
20 namespace {
21 
22 class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
23   IndexingContext &IndexCtx;
24   const NamedDecl *Parent;
25   const DeclContext *ParentDC;
26   bool IsBase;
27   SmallVector<SymbolRelation, 3> Relations;
28 
29   typedef RecursiveASTVisitor<TypeIndexer> base;
30 
31 public:
TypeIndexer(IndexingContext & indexCtx,const NamedDecl * parent,const DeclContext * DC,bool isBase,bool isIBType)32   TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent,
33               const DeclContext *DC, bool isBase, bool isIBType)
34     : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) {
35     if (IsBase) {
36       assert(Parent);
37       Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent);
38     }
39     if (isIBType) {
40       assert(Parent);
41       Relations.emplace_back((unsigned)SymbolRole::RelationIBTypeOf, Parent);
42     }
43   }
44 
shouldWalkTypesOfTypeLocs() const45   bool shouldWalkTypesOfTypeLocs() const { return false; }
46 
47 #define TRY_TO(CALL_EXPR)                                                      \
48   do {                                                                         \
49     if (!CALL_EXPR)                                                            \
50       return false;                                                            \
51   } while (0)
52 
VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL)53   bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL) {
54     SourceLocation Loc = TTPL.getNameLoc();
55     TemplateTypeParmDecl *TTPD = TTPL.getDecl();
56     return IndexCtx.handleReference(TTPD, Loc, Parent, ParentDC,
57                                     SymbolRoleSet());
58   }
59 
VisitTypedefTypeLoc(TypedefTypeLoc TL)60   bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
61     SourceLocation Loc = TL.getNameLoc();
62     TypedefNameDecl *ND = TL.getTypedefNameDecl();
63     if (ND->isTransparentTag()) {
64       TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl();
65       return IndexCtx.handleReference(Underlying, Loc, Parent,
66                                       ParentDC, SymbolRoleSet(), Relations);
67     }
68     if (IsBase) {
69       TRY_TO(IndexCtx.handleReference(ND, Loc,
70                                       Parent, ParentDC, SymbolRoleSet()));
71       if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
72         TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
73                                         (unsigned)SymbolRole::Implicit,
74                                         Relations));
75       }
76     } else {
77       TRY_TO(IndexCtx.handleReference(ND, Loc,
78                                       Parent, ParentDC, SymbolRoleSet(),
79                                       Relations));
80     }
81     return true;
82   }
83 
VisitAutoTypeLoc(AutoTypeLoc TL)84   bool VisitAutoTypeLoc(AutoTypeLoc TL) {
85     if (auto *C = TL.getNamedConcept())
86       return IndexCtx.handleReference(C, TL.getConceptNameLoc(), Parent,
87                                       ParentDC);
88     return true;
89   }
90 
traverseParamVarHelper(ParmVarDecl * D)91   bool traverseParamVarHelper(ParmVarDecl *D) {
92     TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
93     if (D->getTypeSourceInfo())
94       TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
95     return true;
96   }
97 
TraverseParmVarDecl(ParmVarDecl * D)98   bool TraverseParmVarDecl(ParmVarDecl *D) {
99     // Avoid visiting default arguments from the definition that were already
100     // visited in the declaration.
101     // FIXME: A free function definition can have default arguments.
102     // Avoiding double visitaiton of default arguments should be handled by the
103     // visitor probably with a bit in the AST to indicate if the attached
104     // default argument was 'inherited' or written in source.
105     if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) {
106       if (FD->isThisDeclarationADefinition()) {
107         return traverseParamVarHelper(D);
108       }
109     }
110 
111     return base::TraverseParmVarDecl(D);
112   }
113 
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS)114   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
115     IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
116     return true;
117   }
118 
VisitTagTypeLoc(TagTypeLoc TL)119   bool VisitTagTypeLoc(TagTypeLoc TL) {
120     TagDecl *D = TL.getDecl();
121     if (!IndexCtx.shouldIndexFunctionLocalSymbols() &&
122         D->getParentFunctionOrMethod())
123       return true;
124 
125     if (TL.isDefinition()) {
126       IndexCtx.indexTagDecl(D);
127       return true;
128     }
129 
130     return IndexCtx.handleReference(D, TL.getNameLoc(),
131                                     Parent, ParentDC, SymbolRoleSet(),
132                                     Relations);
133   }
134 
VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL)135   bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
136     return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
137                                     Parent, ParentDC, SymbolRoleSet(), Relations);
138   }
139 
VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL)140   bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
141     for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
142       IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
143                                Parent, ParentDC, SymbolRoleSet(), Relations);
144     }
145     return true;
146   }
147 
HandleTemplateSpecializationTypeLoc(TemplateName TemplName,SourceLocation TemplNameLoc,CXXRecordDecl * ResolvedClass,bool IsTypeAlias)148   void HandleTemplateSpecializationTypeLoc(TemplateName TemplName,
149                                            SourceLocation TemplNameLoc,
150                                            CXXRecordDecl *ResolvedClass,
151                                            bool IsTypeAlias) {
152     // In presence of type aliases, the resolved class was never written in
153     // the code so don't report it.
154     if (!IsTypeAlias && ResolvedClass &&
155         (!ResolvedClass->isImplicit() ||
156          IndexCtx.shouldIndexImplicitInstantiation())) {
157       IndexCtx.handleReference(ResolvedClass, TemplNameLoc, Parent, ParentDC,
158                                SymbolRoleSet(), Relations);
159     } else if (const TemplateDecl *D = TemplName.getAsTemplateDecl()) {
160       IndexCtx.handleReference(D, TemplNameLoc, Parent, ParentDC,
161                                SymbolRoleSet(), Relations);
162     }
163   }
164 
VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL)165   bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
166     auto *T = TL.getTypePtr();
167     if (!T)
168       return true;
169     HandleTemplateSpecializationTypeLoc(
170         T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),
171         T->isTypeAlias());
172     return true;
173   }
174 
TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL)175   bool TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
176     if (!WalkUpFromTemplateSpecializationTypeLoc(TL))
177       return false;
178     if (!TraverseTemplateName(TL.getTypePtr()->getTemplateName()))
179       return false;
180 
181     // The relations we have to `Parent` do not apply to our template arguments,
182     // so clear them while visiting the args.
183     SmallVector<SymbolRelation, 3> SavedRelations = Relations;
184     Relations.clear();
185     auto ResetSavedRelations =
186         llvm::make_scope_exit([&] { this->Relations = SavedRelations; });
187     for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
188       if (!TraverseTemplateArgumentLoc(TL.getArgLoc(I)))
189         return false;
190     }
191 
192     return true;
193   }
194 
VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL)195   bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) {
196     auto *T = TL.getTypePtr();
197     if (!T)
198       return true;
199     HandleTemplateSpecializationTypeLoc(
200         T->getTemplateName(), TL.getTemplateNameLoc(), T->getAsCXXRecordDecl(),
201         /*IsTypeAlias=*/false);
202     return true;
203   }
204 
VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL)205   bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
206     return IndexCtx.handleReference(TL.getDecl(), TL.getNameLoc(), Parent,
207                                     ParentDC, SymbolRoleSet(), Relations);
208   }
209 
VisitDependentNameTypeLoc(DependentNameTypeLoc TL)210   bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
211     std::vector<const NamedDecl *> Symbols =
212         IndexCtx.getResolver()->resolveDependentNameType(TL.getTypePtr());
213     if (Symbols.size() != 1)
214       return true;
215     return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
216                                     ParentDC, SymbolRoleSet(), Relations);
217   }
218 
TraverseStmt(Stmt * S)219   bool TraverseStmt(Stmt *S) {
220     IndexCtx.indexBody(S, Parent, ParentDC);
221     return true;
222   }
223 };
224 
225 } // anonymous namespace
226 
indexTypeSourceInfo(TypeSourceInfo * TInfo,const NamedDecl * Parent,const DeclContext * DC,bool isBase,bool isIBType)227 void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
228                                           const NamedDecl *Parent,
229                                           const DeclContext *DC,
230                                           bool isBase,
231                                           bool isIBType) {
232   if (!TInfo || TInfo->getTypeLoc().isNull())
233     return;
234 
235   indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase, isIBType);
236 }
237 
indexTypeLoc(TypeLoc TL,const NamedDecl * Parent,const DeclContext * DC,bool isBase,bool isIBType)238 void IndexingContext::indexTypeLoc(TypeLoc TL,
239                                    const NamedDecl *Parent,
240                                    const DeclContext *DC,
241                                    bool isBase,
242                                    bool isIBType) {
243   if (TL.isNull())
244     return;
245 
246   if (!DC)
247     DC = Parent->getLexicalDeclContext();
248   TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL);
249 }
250 
indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,const NamedDecl * Parent,const DeclContext * DC)251 void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
252                                                   const NamedDecl *Parent,
253                                                   const DeclContext *DC) {
254   if (!NNS)
255     return;
256 
257   if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
258     indexNestedNameSpecifierLoc(Prefix, Parent, DC);
259 
260   if (!DC)
261     DC = Parent->getLexicalDeclContext();
262   SourceLocation Loc = NNS.getLocalBeginLoc();
263 
264   switch (NNS.getNestedNameSpecifier()->getKind()) {
265   case NestedNameSpecifier::Identifier:
266   case NestedNameSpecifier::Global:
267   case NestedNameSpecifier::Super:
268     break;
269 
270   case NestedNameSpecifier::Namespace:
271     handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
272                     Loc, Parent, DC, SymbolRoleSet());
273     break;
274   case NestedNameSpecifier::NamespaceAlias:
275     handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
276                     Loc, Parent, DC, SymbolRoleSet());
277     break;
278 
279   case NestedNameSpecifier::TypeSpec:
280     indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
281     break;
282   }
283 }
284 
indexTagDecl(const TagDecl * D,ArrayRef<SymbolRelation> Relations)285 void IndexingContext::indexTagDecl(const TagDecl *D,
286                                    ArrayRef<SymbolRelation> Relations) {
287   if (!shouldIndex(D))
288     return;
289   if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
290     return;
291 
292   if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
293     if (D->isThisDeclarationADefinition()) {
294       indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
295       if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
296         for (const auto &I : CXXRD->bases()) {
297           indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true);
298         }
299       }
300       indexDeclContext(D);
301     }
302   }
303 }
304