Skip to content

Commit 44573bc

Browse files
[clang][HeuristicResolver] Default argument heuristic for template parameters (#132465)
Fixes clangd/clangd#1056
1 parent 7c52886 commit 44573bc

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

clang/lib/Sema/HeuristicResolver.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clang/AST/CXXInheritance.h"
1212
#include "clang/AST/DeclTemplate.h"
1313
#include "clang/AST/ExprCXX.h"
14+
#include "clang/AST/TemplateBase.h"
1415
#include "clang/AST/Type.h"
1516

1617
namespace clang {
@@ -247,6 +248,20 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,
247248
}
248249
}
249250
}
251+
if (const auto *TTPT = dyn_cast_if_present<TemplateTypeParmType>(T.Type)) {
252+
// We can't do much useful with a template parameter (e.g. we cannot look
253+
// up member names inside it). However, if the template parameter has a
254+
// default argument, as a heuristic we can replace T with the default
255+
// argument type.
256+
if (const auto *TTPD = TTPT->getDecl()) {
257+
if (TTPD->hasDefaultArgument()) {
258+
const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();
259+
if (DefaultArg.getKind() == TemplateArgument::Type) {
260+
return {DefaultArg.getAsType()};
261+
}
262+
}
263+
}
264+
}
250265
return T;
251266
};
252267
// As an additional protection against infinite loops, bound the number of

clang/unittests/Sema/HeuristicResolverTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,40 @@ TEST(HeuristicResolver, MemberExpr_HangIssue126536) {
410410
cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"));
411411
}
412412

413+
TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument) {
414+
std::string Code = R"cpp(
415+
struct Default {
416+
void foo();
417+
};
418+
template <typename T = Default>
419+
void bar(T t) {
420+
t.foo();
421+
}
422+
)cpp";
423+
// Test resolution of "foo" in "t.foo()".
424+
expectResolution(
425+
Code, &HeuristicResolver::resolveMemberExpr,
426+
cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),
427+
cxxMethodDecl(hasName("foo")).bind("output"));
428+
}
429+
430+
TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument_Recursive) {
431+
std::string Code = R"cpp(
432+
struct Default {
433+
void foo();
434+
};
435+
template <typename D = Default, typename T = D>
436+
void bar(T t) {
437+
t.foo();
438+
}
439+
)cpp";
440+
// Test resolution of "foo" in "t.foo()".
441+
expectResolution(
442+
Code, &HeuristicResolver::resolveMemberExpr,
443+
cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input"),
444+
cxxMethodDecl(hasName("foo")).bind("output"));
445+
}
446+
413447
TEST(HeuristicResolver, DeclRefExpr_StaticMethod) {
414448
std::string Code = R"cpp(
415449
template <typename T>

0 commit comments

Comments
 (0)