https://github.com/HighCommander4 created 
https://github.com/llvm/llvm-project/pull/156283

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

>From 45bcf1eee94b6c13d81b6a1049881882c098db2a Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul...@hotmail.com>
Date: Wed, 27 Aug 2025 00:50:30 -0400
Subject: [PATCH] [clangd] Use HeuristicResolver to try to resolve dependent
 'auto'

---
 clang-tools-extra/clangd/AST.cpp              | 21 +++++++++++++++----
 clang-tools-extra/clangd/AST.h                |  4 +++-
 clang-tools-extra/clangd/Hover.cpp            |  4 +++-
 clang-tools-extra/clangd/XRefs.cpp            | 11 ++++++----
 .../refactor/tweaks/ExpandDeducedType.cpp     |  3 ++-
 .../clangd/unittests/ASTTests.cpp             |  3 ++-
 .../clangd/unittests/HoverTests.cpp           |  4 ++--
 .../clangd/unittests/XRefsTests.cpp           | 10 ++++++++-
 .../tweaks/ExpandDeducedTypeTests.cpp         |  4 ++--
 9 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index 2f46ecc92576c..b96a84519e78c 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -29,6 +29,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Index/USRGeneration.h"
+#include "clang/Sema/HeuristicResolver.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallSet.h"
@@ -479,10 +480,12 @@ namespace {
 /// a deduced type set. The AST should be improved to simplify this scenario.
 class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
   SourceLocation SearchedLocation;
+  const HeuristicResolver *Resolver;
 
 public:
-  DeducedTypeVisitor(SourceLocation SearchedLocation)
-      : SearchedLocation(SearchedLocation) {}
+  DeducedTypeVisitor(SourceLocation SearchedLocation,
+                     const HeuristicResolver *Resolver)
+      : SearchedLocation(SearchedLocation), Resolver(Resolver) {}
 
   // Handle auto initializers:
   //- auto i = 1;
@@ -499,6 +502,14 @@ class DeducedTypeVisitor : public 
RecursiveASTVisitor<DeducedTypeVisitor> {
       return true;
 
     if (auto *AT = D->getType()->getContainedAutoType()) {
+      if (AT->isUndeducedAutoType()) {
+        if (const auto *VD = dyn_cast<VarDecl>(D)) {
+          if (Resolver && VD->hasInit()) {
+            DeducedType = Resolver->resolveExprToType(VD->getInit());
+            return true;
+          }
+        }
+      }
       DeducedType = AT->desugar();
     }
     return true;
@@ -608,10 +619,12 @@ class DeducedTypeVisitor : public 
RecursiveASTVisitor<DeducedTypeVisitor> {
 };
 } // namespace
 
-std::optional<QualType> getDeducedType(ASTContext &ASTCtx, SourceLocation Loc) 
{
+std::optional<QualType> getDeducedType(ASTContext &ASTCtx,
+                                       const HeuristicResolver *Resolver,
+                                       SourceLocation Loc) {
   if (!Loc.isValid())
     return {};
-  DeducedTypeVisitor V(Loc);
+  DeducedTypeVisitor V(Loc, Resolver);
   V.TraverseAST(ASTCtx);
   if (V.DeducedType.isNull())
     return std::nullopt;
diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h
index 1538d12172593..2b83595e5b8e9 100644
--- a/clang-tools-extra/clangd/AST.h
+++ b/clang-tools-extra/clangd/AST.h
@@ -31,6 +31,7 @@ namespace clang {
 class SourceManager;
 class Decl;
 class DynTypedNode;
+class HeuristicResolver;
 
 namespace clangd {
 
@@ -167,7 +168,8 @@ QualType declaredType(const TypeDecl *D);
 /// Retrieves the deduced type at a given location (auto, decltype).
 /// It will return the underlying type.
 /// If the type is an undeduced auto, returns the type itself.
-std::optional<QualType> getDeducedType(ASTContext &, SourceLocation Loc);
+std::optional<QualType> getDeducedType(ASTContext &, const HeuristicResolver *,
+                                       SourceLocation Loc);
 
 // Find the abbreviated-function-template `auto` within a type, or returns 
null.
 // Similar to getContainedAutoTypeLoc, but these `auto`s are
diff --git a/clang-tools-extra/clangd/Hover.cpp 
b/clang-tools-extra/clangd/Hover.cpp
index 9eec322fe5963..138544dea99a1 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1309,7 +1309,9 @@ std::optional<HoverInfo> getHover(ParsedAST &AST, 
Position Pos,
       }
     } else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
       HoverCountMetric.record(1, "keyword");
-      if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) {
+      if (auto Deduced =
+              getDeducedType(AST.getASTContext(), AST.getHeuristicResolver(),
+                             Tok.location())) {
         HI = getDeducedTypeHoverContents(*Deduced, Tok, AST.getASTContext(), 
PP,
                                          Index);
         HighlightRange = Tok.range(SM).toCharRange(SM);
diff --git a/clang-tools-extra/clangd/XRefs.cpp 
b/clang-tools-extra/clangd/XRefs.cpp
index a253a630a48cc..18bc29426df29 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -806,7 +806,9 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, 
Position Pos,
     if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
       // go-to-definition on auto should find the definition of the deduced
       // type, if possible
-      if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) {
+      if (auto Deduced =
+              getDeducedType(AST.getASTContext(), AST.getHeuristicResolver(),
+                             Tok.location())) {
         auto LocSym = locateSymbolForType(AST, *Deduced, Index);
         if (!LocSym.empty())
           return LocSym;
@@ -1965,7 +1967,7 @@ std::vector<const CXXRecordDecl *> 
findRecordTypeAt(ParsedAST &AST,
 
 // Return the type most associated with an AST node.
 // This isn't precisely defined: we want "go to type" to do something useful.
-static QualType typeForNode(const ASTContext &Ctx,
+static QualType typeForNode(const ASTContext &Ctx, const HeuristicResolver *H,
                             const SelectionTree::Node *N) {
   // If we're looking at a namespace qualifier, walk up to what it's 
qualifying.
   // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
@@ -1978,7 +1980,7 @@ static QualType typeForNode(const ASTContext &Ctx,
   if (const TypeLoc *TL = N->ASTNode.get<TypeLoc>()) {
     if (llvm::isa<DeducedType>(TL->getTypePtr()))
       if (auto Deduced = getDeducedType(
-              N->getDeclContext().getParentASTContext(), TL->getBeginLoc()))
+              N->getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))
         return *Deduced;
     // Exception: an alias => underlying type.
     if (llvm::isa<TypedefType>(TL->getTypePtr()))
@@ -2161,7 +2163,8 @@ std::vector<LocatedSymbol> findType(ParsedAST &AST, 
Position Pos,
     // information about the type you may have not known before
     // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
     for (const QualType &Type : unwrapFindType(
-             typeForNode(AST.getASTContext(), N), AST.getHeuristicResolver()))
+             typeForNode(AST.getASTContext(), AST.getHeuristicResolver(), N),
+             AST.getHeuristicResolver()))
       llvm::copy(locateSymbolForType(AST, Type, Index),
                  std::back_inserter(LocatedSymbols));
 
diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp 
b/clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
index fec5f5797cb62..52afda56a5028 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
@@ -133,7 +133,8 @@ Expected<Tweak::Effect> ExpandDeducedType::apply(const 
Selection &Inputs) {
   auto &SrcMgr = Inputs.AST->getSourceManager();
 
   std::optional<clang::QualType> DeducedType =
-      getDeducedType(Inputs.AST->getASTContext(), Range.getBegin());
+      getDeducedType(Inputs.AST->getASTContext(),
+                     Inputs.AST->getHeuristicResolver(), Range.getBegin());
 
   // if we can't resolve the type, return an error message
   if (DeducedType == std::nullopt || (*DeducedType)->isUndeducedAutoType())
diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp 
b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index 76d46bad82224..91ae727d8c944 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -244,7 +244,8 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
     for (Position Pos : File.points()) {
       auto Location = sourceLocationInMainFile(SM.get(), Pos);
       ASSERT_TRUE(!!Location) << llvm::toString(Location.takeError());
-      auto DeducedType = getDeducedType(AST.getASTContext(), *Location);
+      auto DeducedType = getDeducedType(AST.getASTContext(),
+                                        AST.getHeuristicResolver(), *Location);
       if (T.DeducedType == nullptr) {
         EXPECT_FALSE(DeducedType);
       } else {
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp 
b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 743c0dc0d0187..e9abf71e6d1b6 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -481,7 +481,7 @@ class Foo final {})cpp";
        [](HoverInfo &HI) {
          HI.Name = "auto";
          HI.Kind = index::SymbolKind::TypeAlias;
-         HI.Definition = "/* not deduced */";
+         HI.Definition = "T";
        }},
       // constrained auto
       {R"cpp(
@@ -2657,7 +2657,7 @@ TEST(Hover, All) {
           [](HoverInfo &HI) {
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
-            HI.Definition = "/* not deduced */";
+            HI.Definition = "T";
           }},
       {
           R"cpp(// Undeduced auto return type
diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp 
b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index 17204a47ba3bc..7ed08d7cce3d3 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -924,11 +924,19 @@ TEST(LocateSymbol, All) {
         }
       )cpp",
 
+      R"cpp(// auto with dependent type
+        template <typename>
+        struct [[A]] {};
+        template <typename T>
+        void foo(A<T> a) {
+          ^auto copy = a;
+        }
+      )cpp",
+
       R"cpp(// Override specifier jumps to overridden method
         class Y { virtual void $decl[[a]]() = 0; };
         class X : Y { void a() ^override {} };
       )cpp",
-
       R"cpp(// Final specifier jumps to overridden method
         class Y { virtual void $decl[[a]]() = 0; };
         class X : Y { void a() ^final {} };
diff --git 
a/clang-tools-extra/clangd/unittests/tweaks/ExpandDeducedTypeTests.cpp 
b/clang-tools-extra/clangd/unittests/tweaks/ExpandDeducedTypeTests.cpp
index 8da394d74b54d..3a53c11839c20 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/ExpandDeducedTypeTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/ExpandDeducedTypeTests.cpp
@@ -47,7 +47,7 @@ TEST_F(ExpandDeducedTypeTest, Test) {
             "namespace ns { void f() { Class C = Class(); } }");
   // undefined functions should not be replaced
   EXPECT_THAT(apply("au^to x = doesnt_exist(); // error-ok"),
-              StartsWith("fail: Could not deduce type for 'auto' type"));
+              StartsWith("fail: Could not expand a dependent type"));
   // function pointers should not be replaced
   EXPECT_THAT(apply("au^to x = &ns::Func;"),
               StartsWith("fail: Could not expand type"));
@@ -91,7 +91,7 @@ TEST_F(ExpandDeducedTypeTest, Test) {
 
   // unknown types in a template should not be replaced
   EXPECT_THAT(apply("template <typename T> void x() { ^auto y = T::z(); }"),
-              StartsWith("fail: Could not deduce type for 'auto' type"));
+              StartsWith("fail: Could not expand a dependent type"));
 
   // check primitive type
   EXPECT_EQ(apply("decl^type(0) i;"), "int i;");

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to