@@ -265,6 +265,102 @@ TEST(QualTypeNameTest, InlineNamespace) {
265265 TypeNameVisitor::Lang_CXX11);
266266}
267267
268+ TEST (QualTypeNameTest, TemplatedClass) {
269+ std::unique_ptr<ASTUnit> AST =
270+ tooling::buildASTFromCode (" template <unsigned U1> struct A {\n "
271+ " template <unsigned U2> struct B {};\n "
272+ " };\n "
273+ " template struct A<1>;\n "
274+ " template struct A<2u>;\n "
275+ " template struct A<1>::B<3>;\n "
276+ " template struct A<2u>::B<4u>;\n " );
277+
278+ auto &Context = AST->getASTContext ();
279+ auto &Policy = Context.getPrintingPolicy ();
280+ auto getFullyQualifiedName = [&](QualType QT) {
281+ return TypeName::getFullyQualifiedName (QT, Context, Policy);
282+ };
283+
284+ auto *A = Context.getTranslationUnitDecl ()
285+ ->lookup (&Context.Idents .get (" A" ))
286+ .find_first <ClassTemplateDecl>();
287+ ASSERT_NE (A, nullptr );
288+
289+ // A has two explicit instantiations: A<1> and A<2u>
290+ auto ASpec = A->spec_begin ();
291+ ASSERT_NE (ASpec, A->spec_end ());
292+ auto *A1 = *ASpec;
293+ ASpec++;
294+ ASSERT_NE (ASpec, A->spec_end ());
295+ auto *A2 = *ASpec;
296+
297+ // Their type names follow the records.
298+ QualType A1RecordTy = Context.getRecordType (A1);
299+ EXPECT_EQ (getFullyQualifiedName (A1RecordTy), " A<1>" );
300+ QualType A2RecordTy = Context.getRecordType (A2);
301+ EXPECT_EQ (getFullyQualifiedName (A2RecordTy), " A<2U>" );
302+
303+ // getTemplateSpecializationType() gives types that print the integral
304+ // argument directly.
305+ TemplateArgument Args1[] = {
306+ {Context, llvm::APSInt::getUnsigned (1u ), Context.UnsignedIntTy }};
307+ QualType A1TemplateSpecTy =
308+ Context.getTemplateSpecializationType (TemplateName (A), Args1, A1RecordTy);
309+ EXPECT_EQ (A1TemplateSpecTy.getAsString (), " A<1>" );
310+
311+ TemplateArgument Args2[] = {
312+ {Context, llvm::APSInt::getUnsigned (2u ), Context.UnsignedIntTy }};
313+ QualType A2TemplateSpecTy =
314+ Context.getTemplateSpecializationType (TemplateName (A), Args2, A2RecordTy);
315+ EXPECT_EQ (A2TemplateSpecTy.getAsString (), " A<2>" );
316+
317+ // Find A<1>::B and its specialization B<3>.
318+ auto *A1B =
319+ A1->lookup (&Context.Idents .get (" B" )).find_first <ClassTemplateDecl>();
320+ ASSERT_NE (A1B, nullptr );
321+ auto A1BSpec = A1B->spec_begin ();
322+ ASSERT_NE (A1BSpec, A1B->spec_end ());
323+ auto *A1B3 = *A1BSpec;
324+ QualType A1B3RecordTy = Context.getRecordType (A1B3);
325+ EXPECT_EQ (getFullyQualifiedName (A1B3RecordTy), " A<1>::B<3>" );
326+
327+ // Construct A<1>::B<3> and check name.
328+ TemplateArgument Args3[] = {
329+ {Context, llvm::APSInt::getUnsigned (3u ), Context.UnsignedIntTy }};
330+ QualType A1B3TemplateSpecTy = Context.getTemplateSpecializationType (
331+ TemplateName (A1B), Args3, A1B3RecordTy);
332+ EXPECT_EQ (A1B3TemplateSpecTy.getAsString (), " B<3>" );
333+
334+ NestedNameSpecifier *A1Nested = NestedNameSpecifier::Create (
335+ Context, nullptr , false , A1TemplateSpecTy.getTypePtr ());
336+ QualType A1B3ElaboratedTy = Context.getElaboratedType (
337+ ElaboratedTypeKeyword::None, A1Nested, A1B3TemplateSpecTy);
338+ EXPECT_EQ (A1B3ElaboratedTy.getAsString (), " A<1>::B<3>" );
339+
340+ // Find A<2u>::B and its specialization B<4u>.
341+ auto *A2B =
342+ A2->lookup (&Context.Idents .get (" B" )).find_first <ClassTemplateDecl>();
343+ ASSERT_NE (A2B, nullptr );
344+ auto A2BSpec = A2B->spec_begin ();
345+ ASSERT_NE (A2BSpec, A2B->spec_end ());
346+ auto *A2B4 = *A2BSpec;
347+ QualType A2B4RecordTy = Context.getRecordType (A2B4);
348+ EXPECT_EQ (getFullyQualifiedName (A2B4RecordTy), " A<2U>::B<4U>" );
349+
350+ // Construct A<2>::B<4> and check name.
351+ TemplateArgument Args4[] = {
352+ {Context, llvm::APSInt::getUnsigned (4u ), Context.UnsignedIntTy }};
353+ QualType A2B4TemplateSpecTy = Context.getTemplateSpecializationType (
354+ TemplateName (A2B), Args4, A2B4RecordTy);
355+ EXPECT_EQ (A2B4TemplateSpecTy.getAsString (), " B<4>" );
356+
357+ NestedNameSpecifier *A2Nested = NestedNameSpecifier::Create (
358+ Context, nullptr , false , A2TemplateSpecTy.getTypePtr ());
359+ QualType A2B4ElaboratedTy = Context.getElaboratedType (
360+ ElaboratedTypeKeyword::None, A2Nested, A2B4TemplateSpecTy);
361+ EXPECT_EQ (A2B4ElaboratedTy.getAsString (), " A<2>::B<4>" );
362+ }
363+
268364TEST (QualTypeNameTest, AnonStrucs) {
269365 TypeNameVisitor AnonStrucs;
270366 AnonStrucs.ExpectedQualTypeNames [" a" ] = " short" ;
0 commit comments