@@ -467,6 +467,13 @@ void ASTPrinter::printEscapedStringLiteral(StringRef str) {
467
467
printTextImpl (escapeBuf.str ());
468
468
}
469
469
470
+ // Returns true if the given declaration is backed by a C++ template
471
+ // specialization.
472
+ static bool isSpecializedCxxDecl (const Decl *D) {
473
+ return D->hasClangNode () &&
474
+ isa<clang::ClassTemplateSpecializationDecl>(D->getClangDecl ());
475
+ }
476
+
470
477
void ASTPrinter::printTypeRef (Type T, const TypeDecl *RefTo, Identifier Name,
471
478
PrintNameContext Context) {
472
479
if (isa<GenericTypeParamDecl>(RefTo)) {
@@ -477,7 +484,7 @@ void ASTPrinter::printTypeRef(Type T, const TypeDecl *RefTo, Identifier Name,
477
484
Context = PrintNameContext::ClassDynamicSelf;
478
485
}
479
486
480
- printName (Name, Context);
487
+ printName (Name, Context, isSpecializedCxxDecl (RefTo) );
481
488
}
482
489
483
490
void ASTPrinter::printModuleRef (ModuleEntity Mod, Identifier Name) {
@@ -576,19 +583,25 @@ ASTPrinter &operator<<(ASTPrinter &printer, tok keyword) {
576
583
}
577
584
578
585
// / Determine whether to escape the given keyword in the given context.
579
- bool swift::escapeIdentifierInContext (Identifier name,
580
- PrintNameContext context ) {
586
+ bool swift::escapeIdentifierInContext (Identifier name, PrintNameContext context,
587
+ bool isSpecializedCxxTemplate ) {
581
588
StringRef keyword = name.str ();
582
589
bool isKeyword = llvm::StringSwitch<bool >(keyword)
583
590
#define KEYWORD (KW ) \
584
591
.Case (#KW, true )
585
592
#include " swift/AST/TokenKinds.def"
586
593
.Default (false );
587
594
595
+ // NB: ClangImporter synthesizes C++ template specializations with Identifiers
596
+ // that contain the full type signature; e.g., a type named literally
597
+ // `X<Y, Z>`. These would normally be interpreted as raw identifiers and
598
+ // escaped with backticks, but we need to avoid that for those specific decls.
599
+
588
600
switch (context) {
589
601
case PrintNameContext::Normal:
590
602
case PrintNameContext::Attribute:
591
- return isKeyword || name.mustAlwaysBeEscaped ();
603
+ return isKeyword ||
604
+ (!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped ());
592
605
case PrintNameContext::Keyword:
593
606
case PrintNameContext::IntroducerKeyword:
594
607
return false ;
@@ -598,18 +611,21 @@ bool swift::escapeIdentifierInContext(Identifier name,
598
611
return isKeyword && keyword != " Self" ;
599
612
600
613
case PrintNameContext::TypeMember:
601
- return isKeyword || !canBeMemberName (keyword) || name.mustAlwaysBeEscaped ();
614
+ return isKeyword || !canBeMemberName (keyword) ||
615
+ (!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped ());
602
616
603
617
case PrintNameContext::FunctionParameterExternal:
604
618
case PrintNameContext::FunctionParameterLocal:
605
619
case PrintNameContext::TupleElement:
606
- return !canBeArgumentLabel (keyword) || name.mustAlwaysBeEscaped ();
620
+ return !canBeArgumentLabel (keyword) ||
621
+ (!isSpecializedCxxTemplate && name.mustAlwaysBeEscaped ());
607
622
}
608
623
609
624
llvm_unreachable (" Unhandled PrintNameContext in switch." );
610
625
}
611
626
612
- void ASTPrinter::printName (Identifier Name, PrintNameContext Context) {
627
+ void ASTPrinter::printName (Identifier Name, PrintNameContext Context,
628
+ bool IsSpecializedCxxTemplate) {
613
629
callPrintNamePre (Context);
614
630
615
631
if (Name.empty ()) {
@@ -618,7 +634,8 @@ void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
618
634
return ;
619
635
}
620
636
621
- bool shouldEscapeIdentifier = escapeIdentifierInContext (Name, Context);
637
+ bool shouldEscapeIdentifier =
638
+ escapeIdentifierInContext (Name, Context, IsSpecializedCxxTemplate);
622
639
623
640
if (shouldEscapeIdentifier)
624
641
*this << " `" ;
@@ -3641,12 +3658,16 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
3641
3658
} else {
3642
3659
Printer.printIntroducerKeyword (" enum" , Options, " " );
3643
3660
printContextIfNeeded (decl);
3644
- recordDeclLoc (decl,
3645
- [&]{
3646
- Printer.printName (decl->getName (), getTypeMemberPrintNameContext (decl));
3647
- }, [&]{ // Signature
3648
- printGenericDeclGenericParams (decl);
3649
- });
3661
+ recordDeclLoc (
3662
+ decl,
3663
+ [&] {
3664
+ Printer.printName (decl->getName (),
3665
+ getTypeMemberPrintNameContext (decl),
3666
+ isSpecializedCxxDecl (decl));
3667
+ },
3668
+ [&] { // Signature
3669
+ printGenericDeclGenericParams (decl);
3670
+ });
3650
3671
printInherited (decl);
3651
3672
printDeclGenericRequirements (decl);
3652
3673
}
@@ -3668,12 +3689,16 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
3668
3689
} else {
3669
3690
Printer.printIntroducerKeyword (" struct" , Options, " " );
3670
3691
printContextIfNeeded (decl);
3671
- recordDeclLoc (decl,
3672
- [&]{
3673
- Printer.printName (decl->getName (), getTypeMemberPrintNameContext (decl));
3674
- }, [&]{ // Signature
3675
- printGenericDeclGenericParams (decl);
3676
- });
3692
+ recordDeclLoc (
3693
+ decl,
3694
+ [&] {
3695
+ Printer.printName (decl->getName (),
3696
+ getTypeMemberPrintNameContext (decl),
3697
+ isSpecializedCxxDecl (decl));
3698
+ },
3699
+ [&] { // Signature
3700
+ printGenericDeclGenericParams (decl);
3701
+ });
3677
3702
printInherited (decl);
3678
3703
printDeclGenericRequirements (decl);
3679
3704
}
@@ -3696,12 +3721,16 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
3696
3721
Printer.printIntroducerKeyword (
3697
3722
decl->isExplicitActor () ? " actor" : " class" , Options, " " );
3698
3723
printContextIfNeeded (decl);
3699
- recordDeclLoc (decl,
3700
- [&]{
3701
- Printer.printName (decl->getName (), getTypeMemberPrintNameContext (decl));
3702
- }, [&]{ // Signature
3703
- printGenericDeclGenericParams (decl);
3704
- });
3724
+ recordDeclLoc (
3725
+ decl,
3726
+ [&] {
3727
+ Printer.printName (decl->getName (),
3728
+ getTypeMemberPrintNameContext (decl),
3729
+ isSpecializedCxxDecl (decl));
3730
+ },
3731
+ [&] { // Signature
3732
+ printGenericDeclGenericParams (decl);
3733
+ });
3705
3734
3706
3735
printInherited (decl);
3707
3736
printDeclGenericRequirements (decl);
0 commit comments