[clang] [clang][HeuristicResolver] Default argument heuristic for template parameters (PR #132465)
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 21 13:15:49 PDT 2025
https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/132465
Fixes https://github.com/clangd/clangd/discussions/1056
>From 2855815b91dd924aa56e98ef00f228fdeac9d81d 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
---
clang/lib/Sema/HeuristicResolver.cpp | 15 ++++++++
.../unittests/Sema/HeuristicResolverTest.cpp | 34 +++++++++++++++++++
2 files changed, 49 insertions(+)
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>
More information about the cfe-commits
mailing list