@@ -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 << " `" ;
@@ -3634,12 +3651,16 @@ void PrintAST::visitEnumDecl(EnumDecl *decl) {
3634
3651
} else {
3635
3652
Printer.printIntroducerKeyword (" enum" , Options, " " );
3636
3653
printContextIfNeeded (decl);
3637
- recordDeclLoc (decl,
3638
- [&]{
3639
- Printer.printName (decl->getName (), getTypeMemberPrintNameContext (decl));
3640
- }, [&]{ // Signature
3641
- printGenericDeclGenericParams (decl);
3642
- });
3654
+ recordDeclLoc (
3655
+ decl,
3656
+ [&] {
3657
+ Printer.printName (decl->getName (),
3658
+ getTypeMemberPrintNameContext (decl),
3659
+ isSpecializedCxxDecl (decl));
3660
+ },
3661
+ [&] { // Signature
3662
+ printGenericDeclGenericParams (decl);
3663
+ });
3643
3664
printInherited (decl);
3644
3665
printDeclGenericRequirements (decl);
3645
3666
}
@@ -3661,12 +3682,16 @@ void PrintAST::visitStructDecl(StructDecl *decl) {
3661
3682
} else {
3662
3683
Printer.printIntroducerKeyword (" struct" , Options, " " );
3663
3684
printContextIfNeeded (decl);
3664
- recordDeclLoc (decl,
3665
- [&]{
3666
- Printer.printName (decl->getName (), getTypeMemberPrintNameContext (decl));
3667
- }, [&]{ // Signature
3668
- printGenericDeclGenericParams (decl);
3669
- });
3685
+ recordDeclLoc (
3686
+ decl,
3687
+ [&] {
3688
+ Printer.printName (decl->getName (),
3689
+ getTypeMemberPrintNameContext (decl),
3690
+ isSpecializedCxxDecl (decl));
3691
+ },
3692
+ [&] { // Signature
3693
+ printGenericDeclGenericParams (decl);
3694
+ });
3670
3695
printInherited (decl);
3671
3696
printDeclGenericRequirements (decl);
3672
3697
}
@@ -3689,12 +3714,16 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
3689
3714
Printer.printIntroducerKeyword (
3690
3715
decl->isExplicitActor () ? " actor" : " class" , Options, " " );
3691
3716
printContextIfNeeded (decl);
3692
- recordDeclLoc (decl,
3693
- [&]{
3694
- Printer.printName (decl->getName (), getTypeMemberPrintNameContext (decl));
3695
- }, [&]{ // Signature
3696
- printGenericDeclGenericParams (decl);
3697
- });
3717
+ recordDeclLoc (
3718
+ decl,
3719
+ [&] {
3720
+ Printer.printName (decl->getName (),
3721
+ getTypeMemberPrintNameContext (decl),
3722
+ isSpecializedCxxDecl (decl));
3723
+ },
3724
+ [&] { // Signature
3725
+ printGenericDeclGenericParams (decl);
3726
+ });
3698
3727
3699
3728
printInherited (decl);
3700
3729
printDeclGenericRequirements (decl);
0 commit comments