1 //===--- HeuristicResolver.cpp ---------------------------*- C++-*-===//
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 "HeuristicResolver.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/DeclTemplate.h"
12 #include "clang/AST/ExprCXX.h"
17 // Convenience lambdas for use as the 'Filter' parameter of
18 // HeuristicResolver::resolveDependentMember().
19 const auto NoFilter
= [](const NamedDecl
*D
) { return true; };
20 const auto NonStaticFilter
= [](const NamedDecl
*D
) {
21 return D
->isCXXInstanceMember();
23 const auto StaticFilter
= [](const NamedDecl
*D
) {
24 return !D
->isCXXInstanceMember();
26 const auto ValueFilter
= [](const NamedDecl
*D
) { return isa
<ValueDecl
>(D
); };
27 const auto TypeFilter
= [](const NamedDecl
*D
) { return isa
<TypeDecl
>(D
); };
28 const auto TemplateFilter
= [](const NamedDecl
*D
) {
29 return isa
<TemplateDecl
>(D
);
32 // Helper function for HeuristicResolver::resolveDependentMember()
33 // which takes a possibly-dependent type `T` and heuristically
34 // resolves it to a CXXRecordDecl in which we can try name lookup.
35 CXXRecordDecl
*resolveTypeToRecordDecl(const Type
*T
) {
38 if (const auto *RT
= T
->getAs
<RecordType
>())
39 return dyn_cast
<CXXRecordDecl
>(RT
->getDecl());
41 if (const auto *ICNT
= T
->getAs
<InjectedClassNameType
>())
42 T
= ICNT
->getInjectedSpecializationType().getTypePtrOrNull();
46 const auto *TST
= T
->getAs
<TemplateSpecializationType
>();
50 const ClassTemplateDecl
*TD
= dyn_cast_or_null
<ClassTemplateDecl
>(
51 TST
->getTemplateName().getAsTemplateDecl());
55 return TD
->getTemplatedDecl();
58 const Type
*HeuristicResolver::getPointeeType(const Type
*T
) const {
62 if (T
->isPointerType())
63 return T
->castAs
<PointerType
>()->getPointeeType().getTypePtrOrNull();
65 // Try to handle smart pointer types.
67 // Look up operator-> in the primary template. If we find one, it's probably a
68 // smart pointer type.
69 auto ArrowOps
= resolveDependentMember(
70 T
, Ctx
.DeclarationNames
.getCXXOperatorName(OO_Arrow
), NonStaticFilter
);
74 // Getting the return type of the found operator-> method decl isn't useful,
75 // because we discarded template arguments to perform lookup in the primary
76 // template scope, so the return type would just have the form U* where U is a
77 // template parameter type.
78 // Instead, just handle the common case where the smart pointer type has the
79 // form of SmartPtr<X, ...>, and assume X is the pointee type.
80 auto *TST
= T
->getAs
<TemplateSpecializationType
>();
83 if (TST
->getNumArgs() == 0)
85 const TemplateArgument
&FirstArg
= TST
->getArg(0);
86 if (FirstArg
.getKind() != TemplateArgument::Type
)
88 return FirstArg
.getAsType().getTypePtrOrNull();
91 std::vector
<const NamedDecl
*> HeuristicResolver::resolveMemberExpr(
92 const CXXDependentScopeMemberExpr
*ME
) const {
93 // If the expression has a qualifier, first try resolving the member
94 // inside the qualifier's type.
95 // Note that we cannot use a NonStaticFilter in either case, for a couple
97 // 1. It's valid to access a static member using instance member syntax,
98 // e.g. `instance.static_member`.
99 // 2. We can sometimes get a CXXDependentScopeMemberExpr for static
100 // member syntax too, e.g. if `X::static_member` occurs inside
101 // an instance method, it's represented as a CXXDependentScopeMemberExpr
102 // with `this` as the base expression as `X` as the qualifier
103 // (which could be valid if `X` names a base class after instantiation).
104 if (NestedNameSpecifier
*NNS
= ME
->getQualifier()) {
105 if (const Type
*QualifierType
= resolveNestedNameSpecifierToType(NNS
)) {
107 resolveDependentMember(QualifierType
, ME
->getMember(), NoFilter
);
113 // If that didn't yield any results, try resolving the member inside
114 // the expression's base type.
115 const Type
*BaseType
= ME
->getBaseType().getTypePtrOrNull();
117 BaseType
= getPointeeType(BaseType
);
121 if (const auto *BT
= BaseType
->getAs
<BuiltinType
>()) {
122 // If BaseType is the type of a dependent expression, it's just
123 // represented as BuiltinType::Dependent which gives us no information. We
124 // can get further by analyzing the dependent expression.
125 Expr
*Base
= ME
->isImplicitAccess() ? nullptr : ME
->getBase();
126 if (Base
&& BT
->getKind() == BuiltinType::Dependent
) {
127 BaseType
= resolveExprToType(Base
);
130 return resolveDependentMember(BaseType
, ME
->getMember(), NoFilter
);
133 std::vector
<const NamedDecl
*> HeuristicResolver::resolveDeclRefExpr(
134 const DependentScopeDeclRefExpr
*RE
) const {
135 return resolveDependentMember(RE
->getQualifier()->getAsType(),
136 RE
->getDeclName(), StaticFilter
);
139 std::vector
<const NamedDecl
*>
140 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr
*CE
) const {
141 const auto *CalleeType
= resolveExprToType(CE
->getCallee());
144 if (const auto *FnTypePtr
= CalleeType
->getAs
<PointerType
>())
145 CalleeType
= FnTypePtr
->getPointeeType().getTypePtr();
146 if (const FunctionType
*FnType
= CalleeType
->getAs
<FunctionType
>()) {
148 resolveTypeToRecordDecl(FnType
->getReturnType().getTypePtr())) {
155 std::vector
<const NamedDecl
*>
156 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr
*CE
) const {
157 if (const auto *ND
= dyn_cast_or_null
<NamedDecl
>(CE
->getCalleeDecl())) {
161 return resolveExprToDecls(CE
->getCallee());
164 std::vector
<const NamedDecl
*> HeuristicResolver::resolveUsingValueDecl(
165 const UnresolvedUsingValueDecl
*UUVD
) const {
166 return resolveDependentMember(UUVD
->getQualifier()->getAsType(),
167 UUVD
->getNameInfo().getName(), ValueFilter
);
170 std::vector
<const NamedDecl
*> HeuristicResolver::resolveDependentNameType(
171 const DependentNameType
*DNT
) const {
172 return resolveDependentMember(
173 resolveNestedNameSpecifierToType(DNT
->getQualifier()),
174 DNT
->getIdentifier(), TypeFilter
);
177 std::vector
<const NamedDecl
*>
178 HeuristicResolver::resolveTemplateSpecializationType(
179 const DependentTemplateSpecializationType
*DTST
) const {
180 return resolveDependentMember(
181 resolveNestedNameSpecifierToType(DTST
->getQualifier()),
182 DTST
->getIdentifier(), TemplateFilter
);
185 const Type
*resolveDeclsToType(const std::vector
<const NamedDecl
*> &Decls
) {
186 if (Decls
.size() != 1) // Names an overload set -- just bail.
188 if (const auto *TD
= dyn_cast
<TypeDecl
>(Decls
[0])) {
189 return TD
->getTypeForDecl();
191 if (const auto *VD
= dyn_cast
<ValueDecl
>(Decls
[0])) {
192 return VD
->getType().getTypePtrOrNull();
197 std::vector
<const NamedDecl
*>
198 HeuristicResolver::resolveExprToDecls(const Expr
*E
) const {
199 if (const auto *ME
= dyn_cast
<CXXDependentScopeMemberExpr
>(E
)) {
200 return resolveMemberExpr(ME
);
202 if (const auto *RE
= dyn_cast
<DependentScopeDeclRefExpr
>(E
)) {
203 return resolveDeclRefExpr(RE
);
205 if (const auto *OE
= dyn_cast
<OverloadExpr
>(E
)) {
206 return {OE
->decls_begin(), OE
->decls_end()};
208 if (const auto *CE
= dyn_cast
<CallExpr
>(E
)) {
209 return resolveTypeOfCallExpr(CE
);
211 if (const auto *ME
= dyn_cast
<MemberExpr
>(E
))
212 return {ME
->getMemberDecl()};
217 const Type
*HeuristicResolver::resolveExprToType(const Expr
*E
) const {
218 std::vector
<const NamedDecl
*> Decls
= resolveExprToDecls(E
);
220 return resolveDeclsToType(Decls
);
222 return E
->getType().getTypePtr();
225 const Type
*HeuristicResolver::resolveNestedNameSpecifierToType(
226 const NestedNameSpecifier
*NNS
) const {
230 // The purpose of this function is to handle the dependent (Kind ==
231 // Identifier) case, but we need to recurse on the prefix because
232 // that may be dependent as well, so for convenience handle
233 // the TypeSpec cases too.
234 switch (NNS
->getKind()) {
235 case NestedNameSpecifier::TypeSpec
:
236 case NestedNameSpecifier::TypeSpecWithTemplate
:
237 return NNS
->getAsType();
238 case NestedNameSpecifier::Identifier
: {
239 return resolveDeclsToType(resolveDependentMember(
240 resolveNestedNameSpecifierToType(NNS
->getPrefix()),
241 NNS
->getAsIdentifier(), TypeFilter
));
249 std::vector
<const NamedDecl
*> HeuristicResolver::resolveDependentMember(
250 const Type
*T
, DeclarationName Name
,
251 llvm::function_ref
<bool(const NamedDecl
*ND
)> Filter
) const {
254 if (auto *ET
= T
->getAs
<EnumType
>()) {
255 auto Result
= ET
->getDecl()->lookup(Name
);
256 return {Result
.begin(), Result
.end()};
258 if (auto *RD
= resolveTypeToRecordDecl(T
)) {
259 if (!RD
->hasDefinition())
261 RD
= RD
->getDefinition();
262 return RD
->lookupDependentName(Name
, Filter
);
267 } // namespace clangd