Skip to content

Commit df9b31f

Browse files
[clang][Sema] Handle undeduced auto types in HeuristicResolver (#124236)
Fixes clangd/clangd#897
1 parent ee05440 commit df9b31f

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

clang/lib/Sema/HeuristicResolver.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(
227227
}
228228

229229
// Try resolving the member inside the expression's base type.
230+
Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
230231
QualType BaseType = ME->getBaseType();
231232
if (ME->isArrow()) {
232233
BaseType = getPointeeType(BaseType);
@@ -237,11 +238,25 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(
237238
// If BaseType is the type of a dependent expression, it's just
238239
// represented as BuiltinType::Dependent which gives us no information. We
239240
// can get further by analyzing the dependent expression.
240-
Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
241241
if (Base && BT->getKind() == BuiltinType::Dependent) {
242242
BaseType = resolveExprToType(Base);
243243
}
244244
}
245+
if (const auto *AT = BaseType->getContainedAutoType()) {
246+
// If BaseType contains a dependent `auto` type, deduction will not have
247+
// been performed on it yet. In simple cases (e.g. `auto` variable with
248+
// initializer), get the approximate type that would result from deduction.
249+
// FIXME: A more accurate implementation would propagate things like the
250+
// `const` in `const auto`.
251+
if (AT->isUndeducedAutoType()) {
252+
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
253+
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
254+
if (VD->hasInit())
255+
BaseType = resolveExprToType(VD->getInit());
256+
}
257+
}
258+
}
259+
}
245260
return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
246261
}
247262

clang/unittests/Sema/HeuristicResolverTest.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,46 @@ TEST(HeuristicResolver, MemberExpr_SmartPointer_Qualified) {
155155
cxxMethodDecl(hasName("find"), isConst()).bind("output"));
156156
}
157157

158+
TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction1) {
159+
std::string Code = R"cpp(
160+
template <typename T>
161+
struct A {
162+
int waldo;
163+
};
164+
template <typename T>
165+
void foo(A<T> a) {
166+
auto copy = a;
167+
copy.waldo;
168+
}
169+
)cpp";
170+
expectResolution(
171+
Code, &HeuristicResolver::resolveMemberExpr,
172+
cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),
173+
fieldDecl(hasName("waldo")).bind("output"));
174+
}
175+
176+
TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction2) {
177+
std::string Code = R"cpp(
178+
struct B {
179+
int waldo;
180+
};
181+
182+
template <typename T>
183+
struct A {
184+
B b;
185+
};
186+
template <typename T>
187+
void foo(A<T> a) {
188+
auto b = a.b;
189+
b.waldo;
190+
}
191+
)cpp";
192+
expectResolution(
193+
Code, &HeuristicResolver::resolveMemberExpr,
194+
cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"),
195+
fieldDecl(hasName("waldo")).bind("output"));
196+
}
197+
158198
TEST(HeuristicResolver, MemberExpr_Chained) {
159199
std::string Code = R"cpp(
160200
struct A { void foo() {} };

0 commit comments

Comments
 (0)