mgehre created this revision. mgehre added reviewers: aaron.ballman, alexfh, hokein, njames93. Herald added a subscriber: xazax.hun. Herald added a project: clang.
Before this PR, `modernize-use-using` would transform the typedef in template <int A> struct InjectedClassName { typedef InjectedClassName b; }; into `using b = InjectedClassName<A>;` and template <int> struct InjectedClassNameWithUnnamedArgument { typedef InjectedClassNameWithUnnamedArgument b; }; into `using b = InjectedClassNameWithUnnamedArgument<>;`. The first fixit is surprising because its different than the code before, but the second fixit doesn't even compile. This PR adds an option to the TypePrinter to print InjectedClassNameType without template parameters (i.e. as written). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D77979 Files: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp clang/include/clang/AST/PrettyPrinter.h clang/lib/AST/TypePrinter.cpp Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ clang/lib/AST/TypePrinter.cpp @@ -1305,7 +1305,12 @@ 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, Index: clang/include/clang/AST/PrettyPrinter.h =================================================================== --- clang/include/clang/AST/PrettyPrinter.h +++ clang/include/clang/AST/PrettyPrinter.h @@ -63,7 +63,7 @@ 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 @@ /// 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 arguments are unnamed, printing them results in + /// invalid C++ code. + unsigned PrintInjectedClassNameWithArguments : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp @@ -278,3 +278,16 @@ // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' // CHECK-FIXES: using EnumT2_CheckTypedefImpactFromAnotherFile = enum { ea2, eb2 }; +template <int A> +struct InjectedClassName { + typedef InjectedClassName b; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using b = InjectedClassName; +}; + +template <int> +struct InjectedClassNameWithUnnamedArgument { + typedef InjectedClassNameWithUnnamedArgument b; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument; +}; Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -58,6 +58,7 @@ printPolicy.SuppressScope = true; printPolicy.ConstantArraySizeAsWritten = true; printPolicy.UseVoidForZeroParams = false; + printPolicy.PrintInjectedClassNameWithArguments = false; std::string Type = MatchedDecl->getUnderlyingType().getAsString(printPolicy); std::string Name = MatchedDecl->getNameAsString();
Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ clang/lib/AST/TypePrinter.cpp @@ -1305,7 +1305,12 @@ 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, Index: clang/include/clang/AST/PrettyPrinter.h =================================================================== --- clang/include/clang/AST/PrettyPrinter.h +++ clang/include/clang/AST/PrettyPrinter.h @@ -63,7 +63,7 @@ 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 @@ /// 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 arguments are unnamed, printing them results in + /// invalid C++ code. + unsigned PrintInjectedClassNameWithArguments : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp @@ -278,3 +278,16 @@ // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' // CHECK-FIXES: using EnumT2_CheckTypedefImpactFromAnotherFile = enum { ea2, eb2 }; +template <int A> +struct InjectedClassName { + typedef InjectedClassName b; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using b = InjectedClassName; +}; + +template <int> +struct InjectedClassNameWithUnnamedArgument { + typedef InjectedClassNameWithUnnamedArgument b; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using b = InjectedClassNameWithUnnamedArgument; +}; Index: clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -58,6 +58,7 @@ printPolicy.SuppressScope = true; printPolicy.ConstantArraySizeAsWritten = true; printPolicy.UseVoidForZeroParams = false; + printPolicy.PrintInjectedClassNameWithArguments = false; std::string Type = MatchedDecl->getUnderlyingType().getAsString(printPolicy); std::string Name = MatchedDecl->getNameAsString();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits