1 //===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===//
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
7 //===----------------------------------------------------------------------===//
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 "llvm/ADT/ScopeExit.h"
16 using namespace clang
;
17 using namespace index
;
21 class TypeIndexer
: public RecursiveASTVisitor
<TypeIndexer
> {
22 IndexingContext
&IndexCtx
;
23 const NamedDecl
*Parent
;
24 const DeclContext
*ParentDC
;
26 SmallVector
<SymbolRelation
, 3> Relations
;
28 typedef RecursiveASTVisitor
<TypeIndexer
> base
;
31 TypeIndexer(IndexingContext
&indexCtx
, const NamedDecl
*parent
,
32 const DeclContext
*DC
, bool isBase
, bool isIBType
)
33 : IndexCtx(indexCtx
), Parent(parent
), ParentDC(DC
), IsBase(isBase
) {
36 Relations
.emplace_back((unsigned)SymbolRole::RelationBaseOf
, Parent
);
40 Relations
.emplace_back((unsigned)SymbolRole::RelationIBTypeOf
, Parent
);
44 bool shouldWalkTypesOfTypeLocs() const { return false; }
46 #define TRY_TO(CALL_EXPR) \
52 bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TTPL
) {
53 SourceLocation Loc
= TTPL
.getNameLoc();
54 TemplateTypeParmDecl
*TTPD
= TTPL
.getDecl();
55 return IndexCtx
.handleReference(TTPD
, Loc
, Parent
, ParentDC
,
59 bool VisitTypedefTypeLoc(TypedefTypeLoc TL
) {
60 SourceLocation Loc
= TL
.getNameLoc();
61 TypedefNameDecl
*ND
= TL
.getTypedefNameDecl();
62 if (ND
->isTransparentTag()) {
63 TagDecl
*Underlying
= ND
->getUnderlyingType()->getAsTagDecl();
64 return IndexCtx
.handleReference(Underlying
, Loc
, Parent
,
65 ParentDC
, SymbolRoleSet(), Relations
);
68 TRY_TO(IndexCtx
.handleReference(ND
, Loc
,
69 Parent
, ParentDC
, SymbolRoleSet()));
70 if (auto *CD
= TL
.getType()->getAsCXXRecordDecl()) {
71 TRY_TO(IndexCtx
.handleReference(CD
, Loc
, Parent
, ParentDC
,
72 (unsigned)SymbolRole::Implicit
,
76 TRY_TO(IndexCtx
.handleReference(ND
, Loc
,
77 Parent
, ParentDC
, SymbolRoleSet(),
83 bool VisitAutoTypeLoc(AutoTypeLoc TL
) {
84 if (auto *C
= TL
.getNamedConcept())
85 return IndexCtx
.handleReference(C
, TL
.getConceptNameLoc(), Parent
,
90 bool traverseParamVarHelper(ParmVarDecl
*D
) {
91 TRY_TO(TraverseNestedNameSpecifierLoc(D
->getQualifierLoc()));
92 if (D
->getTypeSourceInfo())
93 TRY_TO(TraverseTypeLoc(D
->getTypeSourceInfo()->getTypeLoc()));
97 bool TraverseParmVarDecl(ParmVarDecl
*D
) {
98 // Avoid visiting default arguments from the definition that were already
99 // visited in the declaration.
100 // FIXME: A free function definition can have default arguments.
101 // Avoiding double visitaiton of default arguments should be handled by the
102 // visitor probably with a bit in the AST to indicate if the attached
103 // default argument was 'inherited' or written in source.
104 if (auto FD
= dyn_cast
<FunctionDecl
>(D
->getDeclContext())) {
105 if (FD
->isThisDeclarationADefinition()) {
106 return traverseParamVarHelper(D
);
110 return base::TraverseParmVarDecl(D
);
113 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS
) {
114 IndexCtx
.indexNestedNameSpecifierLoc(NNS
, Parent
, ParentDC
);
118 bool VisitTagTypeLoc(TagTypeLoc TL
) {
119 TagDecl
*D
= TL
.getDecl();
120 if (!IndexCtx
.shouldIndexFunctionLocalSymbols() &&
121 D
->getParentFunctionOrMethod())
124 if (TL
.isDefinition()) {
125 IndexCtx
.indexTagDecl(D
);
129 return IndexCtx
.handleReference(D
, TL
.getNameLoc(),
130 Parent
, ParentDC
, SymbolRoleSet(),
134 bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL
) {
135 return IndexCtx
.handleReference(TL
.getIFaceDecl(), TL
.getNameLoc(),
136 Parent
, ParentDC
, SymbolRoleSet(), Relations
);
139 bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL
) {
140 for (unsigned i
= 0, e
= TL
.getNumProtocols(); i
!= e
; ++i
) {
141 IndexCtx
.handleReference(TL
.getProtocol(i
), TL
.getProtocolLoc(i
),
142 Parent
, ParentDC
, SymbolRoleSet(), Relations
);
147 void HandleTemplateSpecializationTypeLoc(TemplateName TemplName
,
148 SourceLocation TemplNameLoc
,
149 CXXRecordDecl
*ResolvedClass
,
151 // In presence of type aliases, the resolved class was never written in
152 // the code so don't report it.
153 if (!IsTypeAlias
&& ResolvedClass
&&
154 (!ResolvedClass
->isImplicit() ||
155 IndexCtx
.shouldIndexImplicitInstantiation())) {
156 IndexCtx
.handleReference(ResolvedClass
, TemplNameLoc
, Parent
, ParentDC
,
157 SymbolRoleSet(), Relations
);
158 } else if (const TemplateDecl
*D
= TemplName
.getAsTemplateDecl()) {
159 IndexCtx
.handleReference(D
, TemplNameLoc
, Parent
, ParentDC
,
160 SymbolRoleSet(), Relations
);
164 bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL
) {
165 auto *T
= TL
.getTypePtr();
168 HandleTemplateSpecializationTypeLoc(
169 T
->getTemplateName(), TL
.getTemplateNameLoc(), T
->getAsCXXRecordDecl(),
174 bool TraverseTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL
) {
175 if (!WalkUpFromTemplateSpecializationTypeLoc(TL
))
177 if (!TraverseTemplateName(TL
.getTypePtr()->getTemplateName()))
180 // The relations we have to `Parent` do not apply to our template arguments,
181 // so clear them while visiting the args.
182 SmallVector
<SymbolRelation
, 3> SavedRelations
= Relations
;
184 auto ResetSavedRelations
=
185 llvm::make_scope_exit([&] { this->Relations
= SavedRelations
; });
186 for (unsigned I
= 0, E
= TL
.getNumArgs(); I
!= E
; ++I
) {
187 if (!TraverseTemplateArgumentLoc(TL
.getArgLoc(I
)))
194 bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL
) {
195 auto *T
= TL
.getTypePtr();
198 HandleTemplateSpecializationTypeLoc(
199 T
->getTemplateName(), TL
.getTemplateNameLoc(), T
->getAsCXXRecordDecl(),
200 /*IsTypeAlias=*/false);
204 bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL
) {
205 return IndexCtx
.handleReference(TL
.getDecl(), TL
.getNameLoc(), Parent
,
206 ParentDC
, SymbolRoleSet(), Relations
);
209 bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL
) {
210 const DependentNameType
*DNT
= TL
.getTypePtr();
211 const NestedNameSpecifier
*NNS
= DNT
->getQualifier();
212 const Type
*T
= NNS
->getAsType();
215 const TemplateSpecializationType
*TST
=
216 T
->getAs
<TemplateSpecializationType
>();
219 TemplateName TN
= TST
->getTemplateName();
220 const ClassTemplateDecl
*TD
=
221 dyn_cast_or_null
<ClassTemplateDecl
>(TN
.getAsTemplateDecl());
224 CXXRecordDecl
*RD
= TD
->getTemplatedDecl();
225 if (!RD
->hasDefinition())
227 RD
= RD
->getDefinition();
228 DeclarationName
Name(DNT
->getIdentifier());
229 std::vector
<const NamedDecl
*> Symbols
= RD
->lookupDependentName(
230 Name
, [](const NamedDecl
*ND
) { return isa
<TypeDecl
>(ND
); });
231 if (Symbols
.size() != 1)
233 return IndexCtx
.handleReference(Symbols
[0], TL
.getNameLoc(), Parent
,
234 ParentDC
, SymbolRoleSet(), Relations
);
237 bool TraverseStmt(Stmt
*S
) {
238 IndexCtx
.indexBody(S
, Parent
, ParentDC
);
243 } // anonymous namespace
245 void IndexingContext::indexTypeSourceInfo(TypeSourceInfo
*TInfo
,
246 const NamedDecl
*Parent
,
247 const DeclContext
*DC
,
250 if (!TInfo
|| TInfo
->getTypeLoc().isNull())
253 indexTypeLoc(TInfo
->getTypeLoc(), Parent
, DC
, isBase
, isIBType
);
256 void IndexingContext::indexTypeLoc(TypeLoc TL
,
257 const NamedDecl
*Parent
,
258 const DeclContext
*DC
,
265 DC
= Parent
->getLexicalDeclContext();
266 TypeIndexer(*this, Parent
, DC
, isBase
, isIBType
).TraverseTypeLoc(TL
);
269 void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS
,
270 const NamedDecl
*Parent
,
271 const DeclContext
*DC
) {
275 if (NestedNameSpecifierLoc Prefix
= NNS
.getPrefix())
276 indexNestedNameSpecifierLoc(Prefix
, Parent
, DC
);
279 DC
= Parent
->getLexicalDeclContext();
280 SourceLocation Loc
= NNS
.getLocalBeginLoc();
282 switch (NNS
.getNestedNameSpecifier()->getKind()) {
283 case NestedNameSpecifier::Identifier
:
284 case NestedNameSpecifier::Global
:
285 case NestedNameSpecifier::Super
:
288 case NestedNameSpecifier::Namespace
:
289 handleReference(NNS
.getNestedNameSpecifier()->getAsNamespace(),
290 Loc
, Parent
, DC
, SymbolRoleSet());
292 case NestedNameSpecifier::NamespaceAlias
:
293 handleReference(NNS
.getNestedNameSpecifier()->getAsNamespaceAlias(),
294 Loc
, Parent
, DC
, SymbolRoleSet());
297 case NestedNameSpecifier::TypeSpec
:
298 case NestedNameSpecifier::TypeSpecWithTemplate
:
299 indexTypeLoc(NNS
.getTypeLoc(), Parent
, DC
);
304 void IndexingContext::indexTagDecl(const TagDecl
*D
,
305 ArrayRef
<SymbolRelation
> Relations
) {
308 if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D
))
311 if (handleDecl(D
, /*Roles=*/SymbolRoleSet(), Relations
)) {
312 if (D
->isThisDeclarationADefinition()) {
313 indexNestedNameSpecifierLoc(D
->getQualifierLoc(), D
);
314 if (auto CXXRD
= dyn_cast
<CXXRecordDecl
>(D
)) {
315 for (const auto &I
: CXXRD
->bases()) {
316 indexTypeSourceInfo(I
.getTypeSourceInfo(), CXXRD
, CXXRD
, /*isBase=*/true);