comparison clang-tools-extra/clangd/HeuristicResolver.cpp @ 221:79ff65ed7e25

LLVM12 Original
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 15 Jun 2021 19:15:29 +0900
parents
children c4bab56944e8
comparison
equal deleted inserted replaced
220:42394fc6a535 221:79ff65ed7e25
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