diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index f352374d4b9100..f6dc5c044a7adc 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -58,6 +58,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { printPolicy.SuppressScope = true; printPolicy.ConstantArraySizeAsWritten = true; printPolicy.UseVoidForZeroParams = false; + printPolicy.PrintInjectedClassNameWithArguments = false; std::string Type = MatchedDecl->getUnderlyingType().getAsString(printPolicy); std::string Name = MatchedDecl->getNameAsString(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp index 8d25dbb956583d..b74e67a17f862c 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp @@ -289,3 +289,16 @@ typedef enum { ea2, eb2 } EnumT2_CheckTypedefImpactFromAnotherFile; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' // CHECK-FIXES: using EnumT2_CheckTypedefImpactFromAnotherFile = enum { ea2, eb2 }; +template +struct InjectedClassName { + typedef InjectedClassName b; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using b = InjectedClassName; +}; + +template +struct InjectedClassNameWithUnnamedArgument { + typedef InjectedClassNameWithUnnamedArgument b; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument; +}; diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 21e5ca94f6c483..65c7e2385677f7 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -63,7 +63,7 @@ struct PrintingPolicy { MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), FullyQualifiedName(false), - PrintCanonicalTypes(false) {} + PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -244,6 +244,11 @@ struct PrintingPolicy { /// Whether to print types as written or canonically. unsigned PrintCanonicalTypes : 1; + /// Whether to print an InjectedClassNameType with template arguments or as + /// written. When a template argument is unnamed, printing it results in + /// invalid C++ code. + unsigned PrintInjectedClassNameWithArguments : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index f000e1f6c9324a..cf82d1a26156e3 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1329,7 +1329,12 @@ void TypePrinter::printTemplateSpecializationAfter( void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, raw_ostream &OS) { - printTemplateSpecializationBefore(T->getInjectedTST(), OS); + if (Policy.PrintInjectedClassNameWithArguments) + return printTemplateSpecializationBefore(T->getInjectedTST(), OS); + + IncludeStrongLifetimeRAII Strong(Policy); + T->getTemplateName().print(OS, Policy); + spaceBeforePlaceHolder(OS); } void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,