Author: Nathan Ridge Date: 2025-01-24T16:11:18-05:00 New Revision: df9b31f1e0cdb8096e9d2e0749e473dd815b39f7
URL: https://github.com/llvm/llvm-project/commit/df9b31f1e0cdb8096e9d2e0749e473dd815b39f7 DIFF: https://github.com/llvm/llvm-project/commit/df9b31f1e0cdb8096e9d2e0749e473dd815b39f7.diff LOG: [clang][Sema] Handle undeduced auto types in HeuristicResolver (#124236) Fixes https://github.com/clangd/clangd/issues/897 Added: Modified: clang/lib/Sema/HeuristicResolver.cpp clang/unittests/Sema/HeuristicResolverTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 2a726fe51d355e..e893afed71d268 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -227,6 +227,7 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( } // Try resolving the member inside the expression's base type. + Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); if (ME->isArrow()) { BaseType = getPointeeType(BaseType); @@ -237,11 +238,25 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( // If BaseType is the type of a dependent expression, it's just // represented as BuiltinType::Dependent which gives us no information. We // can get further by analyzing the dependent expression. - Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); if (Base && BT->getKind() == BuiltinType::Dependent) { BaseType = resolveExprToType(Base); } } + if (const auto *AT = BaseType->getContainedAutoType()) { + // If BaseType contains a dependent `auto` type, deduction will not have + // been performed on it yet. In simple cases (e.g. `auto` variable with + // initializer), get the approximate type that would result from deduction. + // FIXME: A more accurate implementation would propagate things like the + // `const` in `const auto`. + if (AT->isUndeducedAutoType()) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (VD->hasInit()) + BaseType = resolveExprToType(VD->getInit()); + } + } + } + } return resolveDependentMember(BaseType, ME->getMember(), NoFilter); } diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 2cd5486b3227f0..2b775b11719ea7 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -155,6 +155,46 @@ TEST(HeuristicResolver, MemberExpr_SmartPointer_Qualified) { cxxMethodDecl(hasName("find"), isConst()).bind("output")); } +TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction1) { + std::string Code = R"cpp( + template <typename T> + struct A { + int waldo; + }; + template <typename T> + void foo(A<T> a) { + auto copy = a; + copy.waldo; + } + )cpp"; + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"), + fieldDecl(hasName("waldo")).bind("output")); +} + +TEST(HeuristicResolver, MemberExpr_AutoTypeDeduction2) { + std::string Code = R"cpp( + struct B { + int waldo; + }; + + template <typename T> + struct A { + B b; + }; + template <typename T> + void foo(A<T> a) { + auto b = a.b; + b.waldo; + } + )cpp"; + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("waldo")).bind("input"), + fieldDecl(hasName("waldo")).bind("output")); +} + TEST(HeuristicResolver, MemberExpr_Chained) { std::string Code = R"cpp( struct A { void foo() {} }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits