Author: Nathan Ridge Date: 2025-09-17T20:51:52-04:00 New Revision: 43ec53b8493752669dc24a6e2b6c66c4449a9e76
URL: https://github.com/llvm/llvm-project/commit/43ec53b8493752669dc24a6e2b6c66c4449a9e76 DIFF: https://github.com/llvm/llvm-project/commit/43ec53b8493752669dc24a6e2b6c66c4449a9e76.diff LOG: [clang][HeuristicResolver] Default argument heuristic for template template parameters (#156404) Fixes https://github.com/clangd/clangd/issues/2478 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 a7fe4ea28b72c..cbdefaa57aacb 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -259,6 +259,25 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E, } } } + + // Similarly, heuristically replace a template template parameter with its + // default argument if it has one. + if (const auto *TST = + dyn_cast_if_present<TemplateSpecializationType>(T.Type)) { + if (const auto *TTPD = dyn_cast_if_present<TemplateTemplateParmDecl>( + TST->getTemplateName().getAsTemplateDecl())) { + if (TTPD->hasDefaultArgument()) { + const auto &DefaultArg = TTPD->getDefaultArgument().getArgument(); + if (DefaultArg.getKind() == TemplateArgument::Template) { + if (const auto *CTD = dyn_cast_if_present<ClassTemplateDecl>( + DefaultArg.getAsTemplate().getAsTemplateDecl())) { + return {Ctx.getCanonicalTagType(CTD->getTemplatedDecl())}; + } + } + } + } + } + // Check if the expression refers to an explicit object parameter of // templated type. If so, heuristically treat it as having the type of the // enclosing class. diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 0eb14f032f16c..a00632f232ea5 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -558,6 +558,24 @@ TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument_Recursive) { cxxMethodDecl(hasName("foo")).bind("output")); } +TEST(HeuristicResolver, MemberExpr_DefaultTemplateTemplateArgument) { + std::string Code = R"cpp( + template <typename T> + struct vector { + void push_back(T); + }; + template <typename Element, template <typename> class Container = vector> + void foo(Container<Element> c, Element e) { + c.push_back(e); + } + )cpp"; + // Test resolution of "push_back" in "c.push_back(e)". + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("push_back")).bind("input"), + cxxMethodDecl(hasName("push_back")).bind("output")); +} + TEST(HeuristicResolver, MemberExpr_ExplicitObjectParameter) { std::string Code = R"cpp( struct Foo { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
