Author: Nathan Ridge
Date: 2025-03-21T19:15:18-04:00
New Revision: 44573bc1528831b13b17afac158f4860af42570e

URL: 
https://github.com/llvm/llvm-project/commit/44573bc1528831b13b17afac158f4860af42570e
DIFF: 
https://github.com/llvm/llvm-project/commit/44573bc1528831b13b17afac158f4860af42570e.diff

LOG: [clang][HeuristicResolver] Default argument heuristic for template 
parameters (#132465)

Fixes https://github.com/clangd/clangd/discussions/1056

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 7aecd2a73b539..4544d75ea73c4 100644
--- a/clang/lib/Sema/HeuristicResolver.cpp
+++ b/clang/lib/Sema/HeuristicResolver.cpp
@@ -11,6 +11,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
 
 namespace clang {
@@ -247,6 +248,20 @@ QualType HeuristicResolverImpl::simplifyType(QualType 
Type, const Expr *E,
         }
       }
     }
+    if (const auto *TTPT = dyn_cast_if_present<TemplateTypeParmType>(T.Type)) {
+      // We can't do much useful with a template parameter (e.g. we cannot look
+      // up member names inside it). However, if the template parameter has a
+      // default argument, as a heuristic we can replace T with the default
+      // argument type.
+      if (const auto *TTPD = TTPT->getDecl()) {
+        if (TTPD->hasDefaultArgument()) {
+          const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();
+          if (DefaultArg.getKind() == TemplateArgument::Type) {
+            return {DefaultArg.getAsType()};
+          }
+        }
+      }
+    }
     return T;
   };
   // As an additional protection against infinite loops, bound the number of

diff  --git a/clang/unittests/Sema/HeuristicResolverTest.cpp 
b/clang/unittests/Sema/HeuristicResolverTest.cpp
index c7cfe7917c532..f7eb4b23c2ab0 100644
--- a/clang/unittests/Sema/HeuristicResolverTest.cpp
+++ b/clang/unittests/Sema/HeuristicResolverTest.cpp
@@ -410,6 +410,40 @@ TEST(HeuristicResolver, MemberExpr_HangIssue126536) {
       cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"));
 }
 
+TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument) {
+  std::string Code = R"cpp(
+    struct Default {
+      void foo();
+    };
+    template <typename T = Default>
+    void bar(T t) {
+      t.foo();
+    }
+  )cpp";
+  // Test resolution of "foo" in "t.foo()".
+  expectResolution(
+      Code, &HeuristicResolver::resolveMemberExpr,
+      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),
+      cxxMethodDecl(hasName("foo")).bind("output"));
+}
+
+TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument_Recursive) {
+  std::string Code = R"cpp(
+    struct Default {
+      void foo();
+    };
+    template <typename D = Default, typename T = D>
+    void bar(T t) {
+      t.foo();
+    }
+  )cpp";
+  // Test resolution of "foo" in "t.foo()".
+  expectResolution(
+      Code, &HeuristicResolver::resolveMemberExpr,
+      cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),
+      cxxMethodDecl(hasName("foo")).bind("output"));
+}
+
 TEST(HeuristicResolver, DeclRefExpr_StaticMethod) {
   std::string Code = R"cpp(
     template <typename T>


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

Reply via email to