[clang-tidy] modernize-use-using: Fix broken fixit with InjectedClassName
authorMatthias Gehre <gehre.matthias@gmail.com>
Sun, 12 Apr 2020 18:06:31 +0000 (20:06 +0200)
committerMatthias Gehre <gehre.matthias@gmail.com>
Mon, 27 Apr 2020 12:23:23 +0000 (14:23 +0200)
Summary:
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).

Reviewers: aaron.ballman, alexfh, hokein, njames93

Subscribers: xazax.hun, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D77979

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 f352374..f6dc5c0 100644 (file)
@@ -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();
index 8d25dbb..b74e67a 100644 (file)
@@ -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 <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 21e5ca9..65c7e23 100644 (file)
@@ -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;
 };
index f000e1f..cf82d1a 100644 (file)
@@ -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,