Mercurial > hg > CbC > CbC_llvm
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 |