Skip to content

Commit 4370072

Browse files
hahnjotstellar
authored andcommitted
[clang] Forward TPL of NestedNameSpecifier
This avoids type suffixes for integer constants when the type can be inferred from the template parameter, such as the unsigned parameter of A<1> and A<2> in the added test.
1 parent d34d529 commit 4370072

File tree

2 files changed

+106
-7
lines changed

2 files changed

+106
-7
lines changed

clang/lib/AST/NestedNameSpecifier.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,16 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
283283
case TypeSpec: {
284284
const auto *Record =
285285
dyn_cast_or_null<ClassTemplateSpecializationDecl>(getAsRecordDecl());
286-
if (ResolveTemplateArguments && Record) {
286+
const TemplateParameterList *TPL = nullptr;
287+
if (Record) {
288+
TPL = Record->getSpecializedTemplate()->getTemplateParameters();
289+
if (ResolveTemplateArguments) {
287290
// Print the type trait with resolved template parameters.
288291
Record->printName(OS, Policy);
289-
printTemplateArgumentList(
290-
OS, Record->getTemplateArgs().asArray(), Policy,
291-
Record->getSpecializedTemplate()->getTemplateParameters());
292+
printTemplateArgumentList(OS, Record->getTemplateArgs().asArray(),
293+
Policy, TPL);
292294
break;
295+
}
293296
}
294297
const Type *T = getAsType();
295298

@@ -313,16 +316,16 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
313316
TemplateName::Qualified::None);
314317

315318
// Print the template argument list.
316-
printTemplateArgumentList(OS, SpecType->template_arguments(),
317-
InnerPolicy);
319+
printTemplateArgumentList(OS, SpecType->template_arguments(), InnerPolicy,
320+
TPL);
318321
} else if (const auto *DepSpecType =
319322
dyn_cast<DependentTemplateSpecializationType>(T)) {
320323
// Print the template name without its corresponding
321324
// nested-name-specifier.
322325
OS << DepSpecType->getIdentifier()->getName();
323326
// Print the template argument list.
324327
printTemplateArgumentList(OS, DepSpecType->template_arguments(),
325-
InnerPolicy);
328+
InnerPolicy, TPL);
326329
} else {
327330
// Print the type normally
328331
QualType(T, 0).print(OS, InnerPolicy);

clang/unittests/Tooling/QualTypeNamesTest.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
268364
TEST(QualTypeNameTest, AnonStrucs) {
269365
TypeNameVisitor AnonStrucs;
270366
AnonStrucs.ExpectedQualTypeNames["a"] = "short";

0 commit comments

Comments
 (0)