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/CXXInheritance.h"
12 #include "clang/AST/DeclTemplate.h"
13 #include "clang/AST/ExprCXX.h"
14 #include "clang/AST/Type.h"
19 // Convenience lambdas for use as the 'Filter' parameter of
20 // HeuristicResolver::resolveDependentMember().
21 const auto NoFilter
= [](const NamedDecl
*D
) { return true; };
22 const auto NonStaticFilter
= [](const NamedDecl
*D
) {
23 return D
->isCXXInstanceMember();
25 const auto StaticFilter
= [](const NamedDecl
*D
) {
26 return !D
->isCXXInstanceMember();
28 const auto ValueFilter
= [](const NamedDecl
*D
) { return isa
<ValueDecl
>(D
); };
29 const auto TypeFilter
= [](const NamedDecl
*D
) { return isa
<TypeDecl
>(D
); };
30 const auto TemplateFilter
= [](const NamedDecl
*D
) {
31 return isa
<TemplateDecl
>(D
);
36 const Type
*resolveDeclsToType(const std::vector
<const NamedDecl
*> &Decls
,
38 if (Decls
.size() != 1) // Names an overload set -- just bail.
40 if (const auto *TD
= dyn_cast
<TypeDecl
>(Decls
[0])) {
41 return Ctx
.getTypeDeclType(TD
).getTypePtr();
43 if (const auto *VD
= dyn_cast
<ValueDecl
>(Decls
[0])) {
44 return VD
->getType().getTypePtrOrNull();
51 // Helper function for HeuristicResolver::resolveDependentMember()
52 // which takes a possibly-dependent type `T` and heuristically
53 // resolves it to a CXXRecordDecl in which we can try name lookup.
54 CXXRecordDecl
*HeuristicResolver::resolveTypeToRecordDecl(const Type
*T
) const {
57 // Unwrap type sugar such as type aliases.
58 T
= T
->getCanonicalTypeInternal().getTypePtr();
60 if (const auto *DNT
= T
->getAs
<DependentNameType
>()) {
61 T
= resolveDeclsToType(resolveDependentNameType(DNT
), Ctx
);
64 T
= T
->getCanonicalTypeInternal().getTypePtr();
67 if (const auto *RT
= T
->getAs
<RecordType
>())
68 return dyn_cast
<CXXRecordDecl
>(RT
->getDecl());
70 if (const auto *ICNT
= T
->getAs
<InjectedClassNameType
>())
71 T
= ICNT
->getInjectedSpecializationType().getTypePtrOrNull();
75 const auto *TST
= T
->getAs
<TemplateSpecializationType
>();
79 const ClassTemplateDecl
*TD
= dyn_cast_or_null
<ClassTemplateDecl
>(
80 TST
->getTemplateName().getAsTemplateDecl());
84 return TD
->getTemplatedDecl();
87 const Type
*HeuristicResolver::getPointeeType(const Type
*T
) const {
91 if (T
->isPointerType())
92 return T
->castAs
<PointerType
>()->getPointeeType().getTypePtrOrNull();
94 // Try to handle smart pointer types.
96 // Look up operator-> in the primary template. If we find one, it's probably a
97 // smart pointer type.
98 auto ArrowOps
= resolveDependentMember(
99 T
, Ctx
.DeclarationNames
.getCXXOperatorName(OO_Arrow
), NonStaticFilter
);
100 if (ArrowOps
.empty())
103 // Getting the return type of the found operator-> method decl isn't useful,
104 // because we discarded template arguments to perform lookup in the primary
105 // template scope, so the return type would just have the form U* where U is a
106 // template parameter type.
107 // Instead, just handle the common case where the smart pointer type has the
108 // form of SmartPtr<X, ...>, and assume X is the pointee type.
109 auto *TST
= T
->getAs
<TemplateSpecializationType
>();
112 if (TST
->template_arguments().size() == 0)
114 const TemplateArgument
&FirstArg
= TST
->template_arguments()[0];
115 if (FirstArg
.getKind() != TemplateArgument::Type
)
117 return FirstArg
.getAsType().getTypePtrOrNull();
120 std::vector
<const NamedDecl
*> HeuristicResolver::resolveMemberExpr(
121 const CXXDependentScopeMemberExpr
*ME
) const {
122 // If the expression has a qualifier, try resolving the member inside the
124 // Note that we cannot use a NonStaticFilter in either case, for a couple
126 // 1. It's valid to access a static member using instance member syntax,
127 // e.g. `instance.static_member`.
128 // 2. We can sometimes get a CXXDependentScopeMemberExpr for static
129 // member syntax too, e.g. if `X::static_member` occurs inside
130 // an instance method, it's represented as a CXXDependentScopeMemberExpr
131 // with `this` as the base expression as `X` as the qualifier
132 // (which could be valid if `X` names a base class after instantiation).
133 if (NestedNameSpecifier
*NNS
= ME
->getQualifier()) {
134 if (const Type
*QualifierType
= resolveNestedNameSpecifierToType(NNS
)) {
136 resolveDependentMember(QualifierType
, ME
->getMember(), NoFilter
);
141 // Do not proceed to try resolving the member in the expression's base type
142 // without regard to the qualifier, as that could produce incorrect results.
143 // For example, `void foo() { this->Base::foo(); }` shouldn't resolve to
148 // Try resolving the member inside the expression's base type.
149 const Type
*BaseType
= ME
->getBaseType().getTypePtrOrNull();
151 BaseType
= getPointeeType(BaseType
);
155 if (const auto *BT
= BaseType
->getAs
<BuiltinType
>()) {
156 // If BaseType is the type of a dependent expression, it's just
157 // represented as BuiltinType::Dependent which gives us no information. We
158 // can get further by analyzing the dependent expression.
159 Expr
*Base
= ME
->isImplicitAccess() ? nullptr : ME
->getBase();
160 if (Base
&& BT
->getKind() == BuiltinType::Dependent
) {
161 BaseType
= resolveExprToType(Base
);
164 return resolveDependentMember(BaseType
, ME
->getMember(), NoFilter
);
167 std::vector
<const NamedDecl
*> HeuristicResolver::resolveDeclRefExpr(
168 const DependentScopeDeclRefExpr
*RE
) const {
169 return resolveDependentMember(RE
->getQualifier()->getAsType(),
170 RE
->getDeclName(), StaticFilter
);
173 std::vector
<const NamedDecl
*>
174 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr
*CE
) const {
175 const auto *CalleeType
= resolveExprToType(CE
->getCallee());
178 if (const auto *FnTypePtr
= CalleeType
->getAs
<PointerType
>())
179 CalleeType
= FnTypePtr
->getPointeeType().getTypePtr();
180 if (const FunctionType
*FnType
= CalleeType
->getAs
<FunctionType
>()) {
182 resolveTypeToRecordDecl(FnType
->getReturnType().getTypePtr())) {
189 std::vector
<const NamedDecl
*>
190 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr
*CE
) const {
191 if (const auto *ND
= dyn_cast_or_null
<NamedDecl
>(CE
->getCalleeDecl())) {
195 return resolveExprToDecls(CE
->getCallee());
198 std::vector
<const NamedDecl
*> HeuristicResolver::resolveUsingValueDecl(
199 const UnresolvedUsingValueDecl
*UUVD
) const {
200 return resolveDependentMember(UUVD
->getQualifier()->getAsType(),
201 UUVD
->getNameInfo().getName(), ValueFilter
);
204 std::vector
<const NamedDecl
*> HeuristicResolver::resolveDependentNameType(
205 const DependentNameType
*DNT
) const {
206 return resolveDependentMember(
207 resolveNestedNameSpecifierToType(DNT
->getQualifier()),
208 DNT
->getIdentifier(), TypeFilter
);
211 std::vector
<const NamedDecl
*>
212 HeuristicResolver::resolveTemplateSpecializationType(
213 const DependentTemplateSpecializationType
*DTST
) const {
214 return resolveDependentMember(
215 resolveNestedNameSpecifierToType(DTST
->getQualifier()),
216 DTST
->getIdentifier(), TemplateFilter
);
219 std::vector
<const NamedDecl
*>
220 HeuristicResolver::resolveExprToDecls(const Expr
*E
) const {
221 if (const auto *ME
= dyn_cast
<CXXDependentScopeMemberExpr
>(E
)) {
222 return resolveMemberExpr(ME
);
224 if (const auto *RE
= dyn_cast
<DependentScopeDeclRefExpr
>(E
)) {
225 return resolveDeclRefExpr(RE
);
227 if (const auto *OE
= dyn_cast
<OverloadExpr
>(E
)) {
228 return {OE
->decls_begin(), OE
->decls_end()};
230 if (const auto *CE
= dyn_cast
<CallExpr
>(E
)) {
231 return resolveTypeOfCallExpr(CE
);
233 if (const auto *ME
= dyn_cast
<MemberExpr
>(E
))
234 return {ME
->getMemberDecl()};
239 const Type
*HeuristicResolver::resolveExprToType(const Expr
*E
) const {
240 std::vector
<const NamedDecl
*> Decls
= resolveExprToDecls(E
);
242 return resolveDeclsToType(Decls
, Ctx
);
244 return E
->getType().getTypePtr();
247 const Type
*HeuristicResolver::resolveNestedNameSpecifierToType(
248 const NestedNameSpecifier
*NNS
) const {
252 // The purpose of this function is to handle the dependent (Kind ==
253 // Identifier) case, but we need to recurse on the prefix because
254 // that may be dependent as well, so for convenience handle
255 // the TypeSpec cases too.
256 switch (NNS
->getKind()) {
257 case NestedNameSpecifier::TypeSpec
:
258 case NestedNameSpecifier::TypeSpecWithTemplate
:
259 return NNS
->getAsType();
260 case NestedNameSpecifier::Identifier
: {
261 return resolveDeclsToType(
262 resolveDependentMember(
263 resolveNestedNameSpecifierToType(NNS
->getPrefix()),
264 NNS
->getAsIdentifier(), TypeFilter
),
275 bool isOrdinaryMember(const NamedDecl
*ND
) {
276 return ND
->isInIdentifierNamespace(Decl::IDNS_Ordinary
| Decl::IDNS_Tag
|
280 bool findOrdinaryMember(const CXXRecordDecl
*RD
, CXXBasePath
&Path
,
281 DeclarationName Name
) {
282 Path
.Decls
= RD
->lookup(Name
).begin();
283 for (DeclContext::lookup_iterator I
= Path
.Decls
, E
= I
.end(); I
!= E
; ++I
)
284 if (isOrdinaryMember(*I
))
292 bool HeuristicResolver::findOrdinaryMemberInDependentClasses(
293 const CXXBaseSpecifier
*Specifier
, CXXBasePath
&Path
,
294 DeclarationName Name
) const {
296 resolveTypeToRecordDecl(Specifier
->getType().getTypePtr());
299 return findOrdinaryMember(RD
, Path
, Name
);
302 std::vector
<const NamedDecl
*> HeuristicResolver::lookupDependentName(
303 CXXRecordDecl
*RD
, DeclarationName Name
,
304 llvm::function_ref
<bool(const NamedDecl
*ND
)> Filter
) const {
305 std::vector
<const NamedDecl
*> Results
;
307 // Lookup in the class.
308 bool AnyOrdinaryMembers
= false;
309 for (const NamedDecl
*ND
: RD
->lookup(Name
)) {
310 if (isOrdinaryMember(ND
))
311 AnyOrdinaryMembers
= true;
313 Results
.push_back(ND
);
315 if (AnyOrdinaryMembers
)
318 // Perform lookup into our base classes.
321 if (!RD
->lookupInBases(
322 [&](const CXXBaseSpecifier
*Specifier
, CXXBasePath
&Path
) {
323 return findOrdinaryMemberInDependentClasses(Specifier
, Path
, Name
);
325 Paths
, /*LookupInDependent=*/true))
327 for (DeclContext::lookup_iterator I
= Paths
.front().Decls
, E
= I
.end();
329 if (isOrdinaryMember(*I
) && Filter(*I
))
330 Results
.push_back(*I
);
335 std::vector
<const NamedDecl
*> HeuristicResolver::resolveDependentMember(
336 const Type
*T
, DeclarationName Name
,
337 llvm::function_ref
<bool(const NamedDecl
*ND
)> Filter
) const {
340 if (auto *ET
= T
->getAs
<EnumType
>()) {
341 auto Result
= ET
->getDecl()->lookup(Name
);
342 return {Result
.begin(), Result
.end()};
344 if (auto *RD
= resolveTypeToRecordDecl(T
)) {
345 if (!RD
->hasDefinition())
347 RD
= RD
->getDefinition();
348 return lookupDependentName(RD
, Name
, Filter
);
353 } // namespace clangd