[llvm-branch-commits] [clang] [clang-tools-extra] [clang][HeuristicResolver] Default argument heuristic for template parameters (PR #131074)

Nathan Ridge via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Mar 13 23:13:56 PDT 2025


https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/131074

>From aeeb8f20927850b11c66110021fe404576ff084f Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Thu, 13 Mar 2025 01:23:03 -0400
Subject: [PATCH] [clang][HeuristicResolver] Default argument heuristic for
 template parameters

---
 .../clangd/unittests/XRefsTests.cpp             |  2 +-
 clang/lib/Sema/HeuristicResolver.cpp            | 15 +++++++++++++++
 clang/unittests/Sema/HeuristicResolverTest.cpp  | 17 +++++++++++++++++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index e12d7691c58fb..693e965e78a96 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -1091,7 +1091,7 @@ TEST(LocateSymbol, All) {
       )objc",
       R"cpp(
         struct PointerIntPairInfo {
-          static void *getPointer(void *Value);
+          static void *$decl[[getPointer]](void *Value);
         };
 
         template <typename Info = PointerIntPairInfo> struct PointerIntPair {
diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp
index d377379c627db..feda9696b8e05 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 {
@@ -125,6 +126,20 @@ TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {
   if (!T)
     return nullptr;
 
+  // If T is the type of a template parameter, we can't get a useful TagDecl
+  // out of 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 *TTPT = dyn_cast<TemplateTypeParmType>(T)) {
+    if (const auto *TTPD = TTPT->getDecl()) {
+      if (TTPD->hasDefaultArgument()) {
+        const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();
+        if (DefaultArg.getKind() == TemplateArgument::Type) {
+          T = DefaultArg.getAsType().getTypePtrOrNull();
+        }
+      }
+    }
+  }
+
   // Unwrap type sugar such as type aliases.
   T = T->getCanonicalTypeInternal().getTypePtr();
 
diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp
index c7cfe7917c532..5e36108172702 100644
--- a/clang/unittests/Sema/HeuristicResolverTest.cpp
+++ b/clang/unittests/Sema/HeuristicResolverTest.cpp
@@ -410,6 +410,23 @@ 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, DeclRefExpr_StaticMethod) {
   std::string Code = R"cpp(
     template <typename T>



More information about the llvm-branch-commits mailing list