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 NonStaticFilter = [](const NamedDecl *D) {
20   return D->isCXXInstanceMember();
21 };
22 const auto StaticFilter = [](const NamedDecl *D) {
23   return !D->isCXXInstanceMember();
24 };
25 const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
26 const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
27 const auto TemplateFilter = [](const NamedDecl *D) {
28   return isa<TemplateDecl>(D);
29 };
30 
31 // Helper function for HeuristicResolver::resolveDependentMember()
32 // which takes a possibly-dependent type `T` and heuristically
33 // resolves it to a CXXRecordDecl in which we can try name lookup.
34 CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) {
35   assert(T);
36 
37   if (const auto *RT = T->getAs<RecordType>())
38     return dyn_cast<CXXRecordDecl>(RT->getDecl());
39 
40   if (const auto *ICNT = T->getAs<InjectedClassNameType>())
41     T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
42   if (!T)
43     return nullptr;
44 
45   const auto *TST = T->getAs<TemplateSpecializationType>();
46   if (!TST)
47     return nullptr;
48 
49   const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
50       TST->getTemplateName().getAsTemplateDecl());
51   if (!TD)
52     return nullptr;
53 
54   return TD->getTemplatedDecl();
55 }
56 
57 const Type *HeuristicResolver::getPointeeType(const Type *T) const {
58   if (!T)
59     return nullptr;
60 
61   if (T->isPointerType()) {
62     return T->getAs<PointerType>()->getPointeeType().getTypePtrOrNull();
63   }
64 
65   // Try to handle smart pointer types.
66 
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);
71   if (ArrowOps.empty())
72     return nullptr;
73 
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>();
81   if (!TST)
82     return nullptr;
83   if (TST->getNumArgs() == 0)
84     return nullptr;
85   const TemplateArgument &FirstArg = TST->getArg(0);
86   if (FirstArg.getKind() != TemplateArgument::Type)
87     return nullptr;
88   return FirstArg.getAsType().getTypePtrOrNull();
89 }
90 
91 std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
92     const CXXDependentScopeMemberExpr *ME) const {
93   const Type *BaseType = ME->getBaseType().getTypePtrOrNull();
94   if (ME->isArrow()) {
95     BaseType = getPointeeType(BaseType);
96   }
97   if (!BaseType)
98     return {};
99   if (const auto *BT = BaseType->getAs<BuiltinType>()) {
100     // If BaseType is the type of a dependent expression, it's just
101     // represented as BultinType::Dependent which gives us no information. We
102     // can get further by analyzing the depedent expression.
103     Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
104     if (Base && BT->getKind() == BuiltinType::Dependent) {
105       BaseType = resolveExprToType(Base);
106     }
107   }
108   return resolveDependentMember(BaseType, ME->getMember(), NonStaticFilter);
109 }
110 
111 std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
112     const DependentScopeDeclRefExpr *RE) const {
113   return resolveDependentMember(RE->getQualifier()->getAsType(),
114                                 RE->getDeclName(), StaticFilter);
115 }
116 
117 std::vector<const NamedDecl *>
118 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
119   const auto *CalleeType = resolveExprToType(CE->getCallee());
120   if (!CalleeType)
121     return {};
122   if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
123     CalleeType = FnTypePtr->getPointeeType().getTypePtr();
124   if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
125     if (const auto *D =
126             resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
127       return {D};
128     }
129   }
130   return {};
131 }
132 
133 std::vector<const NamedDecl *>
134 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
135   if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
136     return {ND};
137   }
138 
139   return resolveExprToDecls(CE->getCallee());
140 }
141 
142 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
143     const UnresolvedUsingValueDecl *UUVD) const {
144   return resolveDependentMember(UUVD->getQualifier()->getAsType(),
145                                 UUVD->getNameInfo().getName(), ValueFilter);
146 }
147 
148 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
149     const DependentNameType *DNT) const {
150   return resolveDependentMember(
151       resolveNestedNameSpecifierToType(DNT->getQualifier()),
152       DNT->getIdentifier(), TypeFilter);
153 }
154 
155 std::vector<const NamedDecl *>
156 HeuristicResolver::resolveTemplateSpecializationType(
157     const DependentTemplateSpecializationType *DTST) const {
158   return resolveDependentMember(
159       resolveNestedNameSpecifierToType(DTST->getQualifier()),
160       DTST->getIdentifier(), TemplateFilter);
161 }
162 
163 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) {
164   if (Decls.size() != 1) // Names an overload set -- just bail.
165     return nullptr;
166   if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
167     return TD->getTypeForDecl();
168   }
169   if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
170     return VD->getType().getTypePtrOrNull();
171   }
172   return nullptr;
173 }
174 
175 std::vector<const NamedDecl *>
176 HeuristicResolver::resolveExprToDecls(const Expr *E) const {
177   if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
178     return resolveMemberExpr(ME);
179   }
180   if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
181     return resolveDeclRefExpr(RE);
182   }
183   if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
184     return {OE->decls_begin(), OE->decls_end()};
185   }
186   if (const auto *CE = dyn_cast<CallExpr>(E)) {
187     return resolveTypeOfCallExpr(CE);
188   }
189   if (const auto *ME = dyn_cast<MemberExpr>(E))
190     return {ME->getMemberDecl()};
191 
192   return {};
193 }
194 
195 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
196   std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
197   if (!Decls.empty())
198     return resolveDeclsToType(Decls);
199 
200   return E->getType().getTypePtr();
201 }
202 
203 const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
204     const NestedNameSpecifier *NNS) const {
205   if (!NNS)
206     return nullptr;
207 
208   // The purpose of this function is to handle the dependent (Kind ==
209   // Identifier) case, but we need to recurse on the prefix because
210   // that may be dependent as well, so for convenience handle
211   // the TypeSpec cases too.
212   switch (NNS->getKind()) {
213   case NestedNameSpecifier::TypeSpec:
214   case NestedNameSpecifier::TypeSpecWithTemplate:
215     return NNS->getAsType();
216   case NestedNameSpecifier::Identifier: {
217     return resolveDeclsToType(resolveDependentMember(
218         resolveNestedNameSpecifierToType(NNS->getPrefix()),
219         NNS->getAsIdentifier(), TypeFilter));
220   }
221   default:
222     break;
223   }
224   return nullptr;
225 }
226 
227 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
228     const Type *T, DeclarationName Name,
229     llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
230   if (!T)
231     return {};
232   if (auto *ET = T->getAs<EnumType>()) {
233     auto Result = ET->getDecl()->lookup(Name);
234     return {Result.begin(), Result.end()};
235   }
236   if (auto *RD = resolveTypeToRecordDecl(T)) {
237     if (!RD->hasDefinition())
238       return {};
239     RD = RD->getDefinition();
240     return RD->lookupDependentName(Name, Filter);
241   }
242   return {};
243 }
244 
245 } // namespace clangd
246 } // namespace clang