https://github.com/hahnjo created https://github.com/llvm/llvm-project/pull/137804
Recently commit dc17429ae6 removed some code related to template arguments in `NestedNameSpecifier::print` that would not pass on the `TemplateParameterList`. This would cause `printIntegral` to add type suffixes for the `unsigned` parameter, but only for the prefix. Add a regression test to prevent such problems from coming back. >From 53a3c9837ed56fdc7720c45395c8070dbeff02fe Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld <jonas.hahnf...@cern.ch> Date: Tue, 29 Apr 2025 14:25:05 +0200 Subject: [PATCH] [clang] Add test for QualTypes in template class NNS Recently commit dc17429ae6 removed some code related to template arguments in NestedNameSpecifier::print that would not pass on the TemplateParameterList. This would cause printIntegral to add type suffixes for the unsigned parameter, but only for the prefix. Add a regression test to prevent such problems from coming back. --- clang/unittests/Tooling/QualTypeNamesTest.cpp | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/clang/unittests/Tooling/QualTypeNamesTest.cpp b/clang/unittests/Tooling/QualTypeNamesTest.cpp index dc81f0188b4fc..bcf7d8935f792 100644 --- a/clang/unittests/Tooling/QualTypeNamesTest.cpp +++ b/clang/unittests/Tooling/QualTypeNamesTest.cpp @@ -265,6 +265,102 @@ TEST(QualTypeNameTest, InlineNamespace) { TypeNameVisitor::Lang_CXX11); } +TEST(QualTypeNameTest, TemplatedClass) { + std::unique_ptr<ASTUnit> AST = + tooling::buildASTFromCode("template <unsigned U1> struct A {\n" + " template <unsigned U2> struct B {};\n" + "};\n" + "template struct A<1>;\n" + "template struct A<2u>;\n" + "template struct A<1>::B<3>;\n" + "template struct A<2u>::B<4u>;\n"); + + auto &Context = AST->getASTContext(); + auto &Policy = Context.getPrintingPolicy(); + auto getFullyQualifiedName = [&](QualType QT) { + return TypeName::getFullyQualifiedName(QT, Context, Policy); + }; + + auto *A = Context.getTranslationUnitDecl() + ->lookup(&Context.Idents.get("A")) + .find_first<ClassTemplateDecl>(); + ASSERT_NE(A, nullptr); + + // A has two explicit instantiations: A<1> and A<2u> + auto ASpec = A->spec_begin(); + ASSERT_NE(ASpec, A->spec_end()); + auto *A1 = *ASpec; + ASpec++; + ASSERT_NE(ASpec, A->spec_end()); + auto *A2 = *ASpec; + + // Their type names follow the records. + QualType A1RecordTy = Context.getRecordType(A1); + EXPECT_EQ(getFullyQualifiedName(A1RecordTy), "A<1>"); + QualType A2RecordTy = Context.getRecordType(A2); + EXPECT_EQ(getFullyQualifiedName(A2RecordTy), "A<2U>"); + + // getTemplateSpecializationType() gives types that print the integral + // argument directly. + TemplateArgument Args1[] = { + {Context, llvm::APSInt::getUnsigned(1u), Context.UnsignedIntTy}}; + QualType A1TemplateSpecTy = Context.getTemplateSpecializationType( + TemplateName(A), Args1, Args1, A1RecordTy); + EXPECT_EQ(A1TemplateSpecTy.getAsString(), "A<1>"); + + TemplateArgument Args2[] = { + {Context, llvm::APSInt::getUnsigned(2u), Context.UnsignedIntTy}}; + QualType A2TemplateSpecTy = Context.getTemplateSpecializationType( + TemplateName(A), Args2, Args2, A2RecordTy); + EXPECT_EQ(A2TemplateSpecTy.getAsString(), "A<2>"); + + // Find A<1>::B and its specialization B<3>. + auto *A1B = + A1->lookup(&Context.Idents.get("B")).find_first<ClassTemplateDecl>(); + ASSERT_NE(A1B, nullptr); + auto A1BSpec = A1B->spec_begin(); + ASSERT_NE(A1BSpec, A1B->spec_end()); + auto *A1B3 = *A1BSpec; + QualType A1B3RecordTy = Context.getRecordType(A1B3); + EXPECT_EQ(getFullyQualifiedName(A1B3RecordTy), "A<1>::B<3>"); + + // Construct A<1>::B<3> and check name. + TemplateArgument Args3[] = { + {Context, llvm::APSInt::getUnsigned(3u), Context.UnsignedIntTy}}; + QualType A1B3TemplateSpecTy = Context.getTemplateSpecializationType( + TemplateName(A1B), Args3, Args3, A1B3RecordTy); + EXPECT_EQ(A1B3TemplateSpecTy.getAsString(), "B<3>"); + + NestedNameSpecifier *A1Nested = NestedNameSpecifier::Create( + Context, nullptr, A1TemplateSpecTy.getTypePtr()); + QualType A1B3ElaboratedTy = Context.getElaboratedType( + ElaboratedTypeKeyword::None, A1Nested, A1B3TemplateSpecTy); + EXPECT_EQ(A1B3ElaboratedTy.getAsString(), "A<1>::B<3>"); + + // Find A<2u>::B and its specialization B<4u>. + auto *A2B = + A2->lookup(&Context.Idents.get("B")).find_first<ClassTemplateDecl>(); + ASSERT_NE(A2B, nullptr); + auto A2BSpec = A2B->spec_begin(); + ASSERT_NE(A2BSpec, A2B->spec_end()); + auto *A2B4 = *A2BSpec; + QualType A2B4RecordTy = Context.getRecordType(A2B4); + EXPECT_EQ(getFullyQualifiedName(A2B4RecordTy), "A<2U>::B<4U>"); + + // Construct A<2>::B<4> and check name. + TemplateArgument Args4[] = { + {Context, llvm::APSInt::getUnsigned(4u), Context.UnsignedIntTy}}; + QualType A2B4TemplateSpecTy = Context.getTemplateSpecializationType( + TemplateName(A2B), Args4, Args4, A2B4RecordTy); + EXPECT_EQ(A2B4TemplateSpecTy.getAsString(), "B<4>"); + + NestedNameSpecifier *A2Nested = NestedNameSpecifier::Create( + Context, nullptr, A2TemplateSpecTy.getTypePtr()); + QualType A2B4ElaboratedTy = Context.getElaboratedType( + ElaboratedTypeKeyword::None, A2Nested, A2B4TemplateSpecTy); + EXPECT_EQ(A2B4ElaboratedTy.getAsString(), "A<2>::B<4>"); +} + TEST(QualTypeNameTest, AnonStrucs) { TypeNameVisitor AnonStrucs; AnonStrucs.ExpectedQualTypeNames["a"] = "short"; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits