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/DeclTemplate.h"
12 #include "clang/AST/ExprCXX.h"
13 
14 namespace clang {
15 namespace clangd {
16 
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();
22 };
23 const auto StaticFilter = [](const NamedDecl *D) {
24   return !D->isCXXInstanceMember();
25 };
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);
30 };
31 
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) {
36   assert(T);
37 
38   if (const auto *RT = T->getAs<RecordType>())
39     return dyn_cast<CXXRecordDecl>(RT->getDecl());
40 
41   if (const auto *ICNT = T->getAs<InjectedClassNameType>())
42     T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
43   if (!T)
44     return nullptr;
45 
46   const auto *TST = T->getAs<TemplateSpecializationType>();
47   if (!TST)
48     return nullptr;
49 
50   const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
51       TST->getTemplateName().getAsTemplateDecl());
52   if (!TD)
53     return nullptr;
54 
55   return TD->getTemplatedDecl();
56 }
57 
58 const Type *HeuristicResolver::getPointeeType(const Type *T) const {
59   if (!T)
60     return nullptr;
61 
62   if (T->isPointerType()) {
63     return T->getAs<PointerType>()->getPointeeType().getTypePtrOrNull();
64   }
65 
66   // Try to handle smart pointer types.
67 
68   // Look up operator-> in the primary template. If we find one, it's probably a
69   // smart pointer type.
70   auto ArrowOps = resolveDependentMember(
71       T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);
72   if (ArrowOps.empty())
73     return nullptr;
74 
75   // Getting the return type of the found operator-> method decl isn't useful,
76   // because we discarded template arguments to perform lookup in the primary
77   // template scope, so the return type would just have the form U* where U is a
78   // template parameter type.
79   // Instead, just handle the common case where the smart pointer type has the
80   // form of SmartPtr<X, ...>, and assume X is the pointee type.
81   auto *TST = T->getAs<TemplateSpecializationType>();
82   if (!TST)
83     return nullptr;
84   if (TST->getNumArgs() == 0)
85     return nullptr;
86   const TemplateArgument &FirstArg = TST->getArg(0);
87   if (FirstArg.getKind() != TemplateArgument::Type)
88     return nullptr;
89   return FirstArg.getAsType().getTypePtrOrNull();
90 }
91 
92 std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
93     const CXXDependentScopeMemberExpr *ME) const {
94   // If the expression has a qualifier, first try resolving the member
95   // inside the qualifier's type.
96   // Note that we cannot use a NonStaticFilter in either case, for a couple
97   // of reasons:
98   //   1. It's valid to access a static member using instance member syntax,
99   //      e.g. `instance.static_member`.
100   //   2. We can sometimes get a CXXDependentScopeMemberExpr for static
101   //      member syntax too, e.g. if `X::static_member` occurs inside
102   //      an instance method, it's represented as a CXXDependentScopeMemberExpr
103   //      with `this` as the base expression as `X` as the qualifier
104   //      (which could be valid if `X` names a base class after instantiation).
105   if (NestedNameSpecifier *NNS = ME->getQualifier()) {
106     if (const Type *QualifierType = resolveNestedNameSpecifierToType(NNS)) {
107       auto Decls =
108           resolveDependentMember(QualifierType, ME->getMember(), NoFilter);
109       if (!Decls.empty())
110         return Decls;
111     }
112   }
113 
114   // If that didn't yield any results, try resolving the member inside
115   // the expression's base type.
116   const Type *BaseType = ME->getBaseType().getTypePtrOrNull();
117   if (ME->isArrow()) {
118     BaseType = getPointeeType(BaseType);
119   }
120   if (!BaseType)
121     return {};
122   if (const auto *BT = BaseType->getAs<BuiltinType>()) {
123     // If BaseType is the type of a dependent expression, it's just
124     // represented as BultinType::Dependent which gives us no information. We
125     // can get further by analyzing the depedent expression.
126     Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
127     if (Base && BT->getKind() == BuiltinType::Dependent) {
128       BaseType = resolveExprToType(Base);
129     }
130   }
131   return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
132 }
133 
134 std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
135     const DependentScopeDeclRefExpr *RE) const {
136   return resolveDependentMember(RE->getQualifier()->getAsType(),
137                                 RE->getDeclName(), StaticFilter);
138 }
139 
140 std::vector<const NamedDecl *>
141 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
142   const auto *CalleeType = resolveExprToType(CE->getCallee());
143   if (!CalleeType)
144     return {};
145   if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
146     CalleeType = FnTypePtr->getPointeeType().getTypePtr();
147   if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
148     if (const auto *D =
149             resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
150       return {D};
151     }
152   }
153   return {};
154 }
155 
156 std::vector<const NamedDecl *>
157 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
158   if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
159     return {ND};
160   }
161 
162   return resolveExprToDecls(CE->getCallee());
163 }
164 
165 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
166     const UnresolvedUsingValueDecl *UUVD) const {
167   return resolveDependentMember(UUVD->getQualifier()->getAsType(),
168                                 UUVD->getNameInfo().getName(), ValueFilter);
169 }
170 
171 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
172     const DependentNameType *DNT) const {
173   return resolveDependentMember(
174       resolveNestedNameSpecifierToType(DNT->getQualifier()),
175       DNT->getIdentifier(), TypeFilter);
176 }
177 
178 std::vector<const NamedDecl *>
179 HeuristicResolver::resolveTemplateSpecializationType(
180     const DependentTemplateSpecializationType *DTST) const {
181   return resolveDependentMember(
182       resolveNestedNameSpecifierToType(DTST->getQualifier()),
183       DTST->getIdentifier(), TemplateFilter);
184 }
185 
186 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) {
187   if (Decls.size() != 1) // Names an overload set -- just bail.
188     return nullptr;
189   if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
190     return TD->getTypeForDecl();
191   }
192   if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
193     return VD->getType().getTypePtrOrNull();
194   }
195   return nullptr;
196 }
197 
198 std::vector<const NamedDecl *>
199 HeuristicResolver::resolveExprToDecls(const Expr *E) const {
200   if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
201     return resolveMemberExpr(ME);
202   }
203   if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
204     return resolveDeclRefExpr(RE);
205   }
206   if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
207     return {OE->decls_begin(), OE->decls_end()};
208   }
209   if (const auto *CE = dyn_cast<CallExpr>(E)) {
210     return resolveTypeOfCallExpr(CE);
211   }
212   if (const auto *ME = dyn_cast<MemberExpr>(E))
213     return {ME->getMemberDecl()};
214 
215   return {};
216 }
217 
218 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
219   std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
220   if (!Decls.empty())
221     return resolveDeclsToType(Decls);
222 
223   return E->getType().getTypePtr();
224 }
225 
226 const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
227     const NestedNameSpecifier *NNS) const {
228   if (!NNS)
229     return nullptr;
230 
231   // The purpose of this function is to handle the dependent (Kind ==
232   // Identifier) case, but we need to recurse on the prefix because
233   // that may be dependent as well, so for convenience handle
234   // the TypeSpec cases too.
235   switch (NNS->getKind()) {
236   case NestedNameSpecifier::TypeSpec:
237   case NestedNameSpecifier::TypeSpecWithTemplate:
238     return NNS->getAsType();
239   case NestedNameSpecifier::Identifier: {
240     return resolveDeclsToType(resolveDependentMember(
241         resolveNestedNameSpecifierToType(NNS->getPrefix()),
242         NNS->getAsIdentifier(), TypeFilter));
243   }
244   default:
245     break;
246   }
247   return nullptr;
248 }
249 
250 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
251     const Type *T, DeclarationName Name,
252     llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
253   if (!T)
254     return {};
255   if (auto *ET = T->getAs<EnumType>()) {
256     auto Result = ET->getDecl()->lookup(Name);
257     return {Result.begin(), Result.end()};
258   }
259   if (auto *RD = resolveTypeToRecordDecl(T)) {
260     if (!RD->hasDefinition())
261       return {};
262     RD = RD->getDefinition();
263     return RD->lookupDependentName(Name, Filter);
264   }
265   return {};
266 }
267 
268 } // namespace clangd
269 } // namespace clang
270