@@ -74,6 +74,15 @@ class HeuristicResolverImpl {
74
74
// resolves it to a TagDecl in which we can try name lookup.
75
75
TagDecl *resolveTypeToTagDecl (const Type *T);
76
76
77
+ // Helper function for simplifying a type.
78
+ // `Type` is the type to simplify.
79
+ // `E` is the expression whose type `Type` is, if known. This sometimes
80
+ // contains information relevant to the type that's not stored in `Type`
81
+ // itself.
82
+ // If `UnwrapPointer` is true, exactly only pointer type will be unwrapped
83
+ // during simplification, and the operation fails if no pointer type is found.
84
+ QualType simplifyType (QualType Type, const Expr *E, bool UnwrapPointer);
85
+
77
86
// This is a reimplementation of CXXRecordDecl::lookupDependentName()
78
87
// so that the implementation can call into other HeuristicResolver helpers.
79
88
// FIXME: Once HeuristicResolver is upstreamed to the clang libraries
@@ -198,6 +207,57 @@ QualType HeuristicResolverImpl::getPointeeType(QualType T) {
198
207
return FirstArg.getAsType ();
199
208
}
200
209
210
+ QualType HeuristicResolverImpl::simplifyType (QualType Type, const Expr *E,
211
+ bool UnwrapPointer) {
212
+ bool DidUnwrapPointer = false ;
213
+ auto SimplifyOneStep = [&](QualType T) {
214
+ if (UnwrapPointer) {
215
+ if (QualType Pointee = getPointeeType (T); !Pointee.isNull ()) {
216
+ DidUnwrapPointer = true ;
217
+ return Pointee;
218
+ }
219
+ }
220
+ if (const auto *RT = T->getAs <ReferenceType>()) {
221
+ // Does not count as "unwrap pointer".
222
+ return RT->getPointeeType ();
223
+ }
224
+ if (const auto *BT = T->getAs <BuiltinType>()) {
225
+ // If BaseType is the type of a dependent expression, it's just
226
+ // represented as BuiltinType::Dependent which gives us no information. We
227
+ // can get further by analyzing the dependent expression.
228
+ if (E && BT->getKind () == BuiltinType::Dependent) {
229
+ return resolveExprToType (E);
230
+ }
231
+ }
232
+ if (const auto *AT = T->getContainedAutoType ()) {
233
+ // If T contains a dependent `auto` type, deduction will not have
234
+ // been performed on it yet. In simple cases (e.g. `auto` variable with
235
+ // initializer), get the approximate type that would result from
236
+ // deduction.
237
+ // FIXME: A more accurate implementation would propagate things like the
238
+ // `const` in `const auto`.
239
+ if (E && AT->isUndeducedAutoType ()) {
240
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
241
+ if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl ())) {
242
+ if (VD->hasInit ())
243
+ return resolveExprToType (VD->getInit ());
244
+ }
245
+ }
246
+ }
247
+ }
248
+ return T;
249
+ };
250
+ while (!Type.isNull ()) {
251
+ QualType New = SimplifyOneStep (Type);
252
+ if (New == Type)
253
+ break ;
254
+ Type = New;
255
+ }
256
+ if (UnwrapPointer && !DidUnwrapPointer)
257
+ return QualType ();
258
+ return Type;
259
+ }
260
+
201
261
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr (
202
262
const CXXDependentScopeMemberExpr *ME) {
203
263
// If the expression has a qualifier, try resolving the member inside the
@@ -230,36 +290,7 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(
230
290
// Try resolving the member inside the expression's base type.
231
291
Expr *Base = ME->isImplicitAccess () ? nullptr : ME->getBase ();
232
292
QualType BaseType = ME->getBaseType ();
233
- if (ME->isArrow ()) {
234
- BaseType = getPointeeType (BaseType);
235
- if (BaseType.isNull ())
236
- return {};
237
- }
238
- if (const auto *BT = BaseType->getAs <BuiltinType>()) {
239
- // If BaseType is the type of a dependent expression, it's just
240
- // represented as BuiltinType::Dependent which gives us no information. We
241
- // can get further by analyzing the dependent expression.
242
- if (Base && BT->getKind () == BuiltinType::Dependent) {
243
- BaseType = resolveExprToType (Base);
244
- if (BaseType.isNull ())
245
- return {};
246
- }
247
- }
248
- if (const auto *AT = BaseType->getContainedAutoType ()) {
249
- // If BaseType contains a dependent `auto` type, deduction will not have
250
- // been performed on it yet. In simple cases (e.g. `auto` variable with
251
- // initializer), get the approximate type that would result from deduction.
252
- // FIXME: A more accurate implementation would propagate things like the
253
- // `const` in `const auto`.
254
- if (AT->isUndeducedAutoType ()) {
255
- if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
256
- if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl ())) {
257
- if (VD->hasInit ())
258
- BaseType = resolveExprToType (VD->getInit ());
259
- }
260
- }
261
- }
262
- }
293
+ BaseType = simplifyType (BaseType, Base, ME->isArrow ());
263
294
return resolveDependentMember (BaseType, ME->getMember (), NoFilter);
264
295
}
265
296
0 commit comments