1//===--- HeuristicResolver.cpp ---------------------------*- C++-*-===//
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 "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"
15
16namespace clang {
17namespace clangd {
18
19// Convenience lambdas for use as the 'Filter' parameter of
20// HeuristicResolver::resolveDependentMember().
21const auto NoFilter = [](const NamedDecl *D) { return true; };
22const auto NonStaticFilter = [](const NamedDecl *D) {
23 return D->isCXXInstanceMember();
24};
25const auto StaticFilter = [](const NamedDecl *D) {
26 return !D->isCXXInstanceMember();
27};
28const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
29const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
30const auto TemplateFilter = [](const NamedDecl *D) {
31 return isa<TemplateDecl>(D);
32};
33
34namespace {
35
36const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
37 ASTContext &Ctx) {
38 if (Decls.size() != 1) // Names an overload set -- just bail.
39 return nullptr;
40 if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
41 return Ctx.getTypeDeclType(TD).getTypePtr();
42 }
43 if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
44 return VD->getType().getTypePtrOrNull();
45 }
46 return nullptr;
47}
48
49} // namespace
50
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.
54CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const {
55 assert(T);
56
57 // Unwrap type sugar such as type aliases.
58 T = T->getCanonicalTypeInternal().getTypePtr();
59
60 if (const auto *DNT = T->getAs<DependentNameType>()) {
61 T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx);
62 if (!T)
63 return nullptr;
64 T = T->getCanonicalTypeInternal().getTypePtr();
65 }
66
67 if (const auto *RT = T->getAs<RecordType>())
68 return dyn_cast<CXXRecordDecl>(RT->getDecl());
69
70 if (const auto *ICNT = T->getAs<InjectedClassNameType>())
71 T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
72 if (!T)
73 return nullptr;
74
75 const auto *TST = T->getAs<TemplateSpecializationType>();
76 if (!TST)
77 return nullptr;
78
79 const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
80 TST->getTemplateName().getAsTemplateDecl());
81 if (!TD)
82 return nullptr;
83
84 return TD->getTemplatedDecl();
85}
86
87const Type *HeuristicResolver::getPointeeType(const Type *T) const {
88 if (!T)
89 return nullptr;
90
91 if (T->isPointerType())
92 return T->castAs<PointerType>()->getPointeeType().getTypePtrOrNull();
93
94 // Try to handle smart pointer types.
95
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())
101 return nullptr;
102
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>();
110 if (!TST)
111 return nullptr;
112 if (TST->template_arguments().size() == 0)
113 return nullptr;
114 const TemplateArgument &FirstArg = TST->template_arguments()[0];
115 if (FirstArg.getKind() != TemplateArgument::Type)
116 return nullptr;
117 return FirstArg.getAsType().getTypePtrOrNull();
118}
119
120std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
121 const CXXDependentScopeMemberExpr *ME) const {
122 // If the expression has a qualifier, first try resolving the member
123 // inside the qualifier's type.
124 // Note that we cannot use a NonStaticFilter in either case, for a couple
125 // of reasons:
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)) {
135 auto Decls =
136 resolveDependentMember(QualifierType, ME->getMember(), NoFilter);
137 if (!Decls.empty())
138 return Decls;
139 }
140 }
141
142 // If that didn't yield any results, try resolving the member inside
143 // the expression's base type.
144 const Type *BaseType = ME->getBaseType().getTypePtrOrNull();
145 if (ME->isArrow()) {
146 BaseType = getPointeeType(BaseType);
147 }
148 if (!BaseType)
149 return {};
150 if (const auto *BT = BaseType->getAs<BuiltinType>()) {
151 // If BaseType is the type of a dependent expression, it's just
152 // represented as BuiltinType::Dependent which gives us no information. We
153 // can get further by analyzing the dependent expression.
154 Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
155 if (Base && BT->getKind() == BuiltinType::Dependent) {
156 BaseType = resolveExprToType(Base);
157 }
158 }
159 return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
160}
161
162std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
163 const DependentScopeDeclRefExpr *RE) const {
164 return resolveDependentMember(RE->getQualifier()->getAsType(),
165 RE->getDeclName(), StaticFilter);
166}
167
168std::vector<const NamedDecl *>
169HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
170 const auto *CalleeType = resolveExprToType(CE->getCallee());
171 if (!CalleeType)
172 return {};
173 if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
174 CalleeType = FnTypePtr->getPointeeType().getTypePtr();
175 if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
176 if (const auto *D =
177 resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
178 return {D};
179 }
180 }
181 return {};
182}
183
184std::vector<const NamedDecl *>
185HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
186 if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
187 return {ND};
188 }
189
190 return resolveExprToDecls(CE->getCallee());
191}
192
193std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
194 const UnresolvedUsingValueDecl *UUVD) const {
195 return resolveDependentMember(UUVD->getQualifier()->getAsType(),
196 UUVD->getNameInfo().getName(), ValueFilter);
197}
198
199std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
200 const DependentNameType *DNT) const {
201 return resolveDependentMember(
202 resolveNestedNameSpecifierToType(DNT->getQualifier()),
203 DNT->getIdentifier(), TypeFilter);
204}
205
206std::vector<const NamedDecl *>
207HeuristicResolver::resolveTemplateSpecializationType(
208 const DependentTemplateSpecializationType *DTST) const {
209 return resolveDependentMember(
210 resolveNestedNameSpecifierToType(DTST->getQualifier()),
211 DTST->getIdentifier(), TemplateFilter);
212}
213
214std::vector<const NamedDecl *>
215HeuristicResolver::resolveExprToDecls(const Expr *E) const {
216 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
217 return resolveMemberExpr(ME);
218 }
219 if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
220 return resolveDeclRefExpr(RE);
221 }
222 if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
223 return {OE->decls_begin(), OE->decls_end()};
224 }
225 if (const auto *CE = dyn_cast<CallExpr>(E)) {
226 return resolveTypeOfCallExpr(CE);
227 }
228 if (const auto *ME = dyn_cast<MemberExpr>(E))
229 return {ME->getMemberDecl()};
230
231 return {};
232}
233
234const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
235 std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
236 if (!Decls.empty())
237 return resolveDeclsToType(Decls, Ctx);
238
239 return E->getType().getTypePtr();
240}
241
242const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
243 const NestedNameSpecifier *NNS) const {
244 if (!NNS)
245 return nullptr;
246
247 // The purpose of this function is to handle the dependent (Kind ==
248 // Identifier) case, but we need to recurse on the prefix because
249 // that may be dependent as well, so for convenience handle
250 // the TypeSpec cases too.
251 switch (NNS->getKind()) {
252 case NestedNameSpecifier::TypeSpec:
253 case NestedNameSpecifier::TypeSpecWithTemplate:
254 return NNS->getAsType();
255 case NestedNameSpecifier::Identifier: {
256 return resolveDeclsToType(
257 resolveDependentMember(
258 resolveNestedNameSpecifierToType(NNS->getPrefix()),
259 NNS->getAsIdentifier(), TypeFilter),
260 Ctx);
261 }
262 default:
263 break;
264 }
265 return nullptr;
266}
267
268namespace {
269
270bool isOrdinaryMember(const NamedDecl *ND) {
271 return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
272 Decl::IDNS_Member);
273}
274
275bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
276 DeclarationName Name) {
277 Path.Decls = RD->lookup(Name).begin();
278 for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
279 if (isOrdinaryMember(*I))
280 return true;
281
282 return false;
283}
284
285} // namespace
286
287bool HeuristicResolver::findOrdinaryMemberInDependentClasses(
288 const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
289 DeclarationName Name) const {
290 CXXRecordDecl *RD =
291 resolveTypeToRecordDecl(Specifier->getType().getTypePtr());
292 if (!RD)
293 return false;
294 return findOrdinaryMember(RD, Path, Name);
295}
296
297std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
298 CXXRecordDecl *RD, DeclarationName Name,
299 llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
300 std::vector<const NamedDecl *> Results;
301
302 // Lookup in the class.
303 bool AnyOrdinaryMembers = false;
304 for (const NamedDecl *ND : RD->lookup(Name)) {
305 if (isOrdinaryMember(ND))
306 AnyOrdinaryMembers = true;
307 if (Filter(ND))
308 Results.push_back(ND);
309 }
310 if (AnyOrdinaryMembers)
311 return Results;
312
313 // Perform lookup into our base classes.
314 CXXBasePaths Paths;
315 Paths.setOrigin(RD);
316 if (!RD->lookupInBases(
317 [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
318 return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);
319 },
320 Paths, /*LookupInDependent=*/true))
321 return Results;
322 for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();
323 I != E; ++I) {
324 if (isOrdinaryMember(*I) && Filter(*I))
325 Results.push_back(*I);
326 }
327 return Results;
328}
329
330std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
331 const Type *T, DeclarationName Name,
332 llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
333 if (!T)
334 return {};
335 if (auto *ET = T->getAs<EnumType>()) {
336 auto Result = ET->getDecl()->lookup(Name);
337 return {Result.begin(), Result.end()};
338 }
339 if (auto *RD = resolveTypeToRecordDecl(T)) {
340 if (!RD->hasDefinition())
341 return {};
342 RD = RD->getDefinition();
343 return lookupDependentName(RD, Name, Filter);
344 }
345 return {};
346}
347
348} // namespace clangd
349} // namespace clang
350