[clang] [clang][Sema] Handle undeduced auto types in HeuristicResolver (PR #124236)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 23 22:59:10 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Nathan Ridge (HighCommander4)

<details>
<summary>Changes</summary>

Fixes https://github.com/clangd/clangd/issues/897

---
Full diff: https://github.com/llvm/llvm-project/pull/124236.diff


2 Files Affected:

- (modified) clang/lib/Sema/HeuristicResolver.cpp (+17-1) 
- (modified) clang/unittests/Sema/HeuristicResolverTest.cpp (+40) 


``````````diff
diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp
index 2a726fe51d355e..92045eb33a4816 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,26 @@ 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() {} };

``````````

</details>


https://github.com/llvm/llvm-project/pull/124236


More information about the cfe-commits mailing list