malcolm.parsons updated this revision to Diff 79627.
malcolm.parsons added a comment.

Handle templated member functions too.


https://reviews.llvm.org/D27166

Files:
  clang-tidy/modernize/UseAutoCheck.cpp
  docs/clang-tidy/checks/modernize-use-auto.rst
  test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
  test/clang-tidy/modernize-use-auto-cast.cpp

Index: test/clang-tidy/modernize-use-auto-cast.cpp
===================================================================
--- test/clang-tidy/modernize-use-auto-cast.cpp
+++ test/clang-tidy/modernize-use-auto-cast.cpp
@@ -138,3 +138,72 @@
   B b;
   A a = A(b);
 }
+
+class StringRef
+{
+public:
+  StringRef(const char *);
+};
+
+template <typename T, typename U>
+T template_value_cast(const U &u);
+
+template <typename T, typename U>
+T *template_pointer_cast(U *u);
+
+template <typename T, typename U>
+T &template_reference_cast(U &u);
+
+template <typename T, typename U>
+const T *template_const_pointer_cast(const U *u);
+
+template <typename T, typename U>
+const T &template_const_reference_cast(const U &u);
+
+template <typename T>
+T template_value_get(StringRef s);
+
+struct S {
+  template <typename T>
+  const T *template_member_get();
+};
+
+template <typename T>
+T max(T t1, T t2);
+
+void f_template_cast()
+{
+  double d = 0;
+  int i1 = template_value_cast<int>(d);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto i1 = template_value_cast<int>(d);
+
+  A *a = new B();
+  B *b1 = template_value_cast<B *>(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto *b1 = template_value_cast<B *>(a);
+  B &b2 = template_value_cast<B &>(*a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a);
+  B *b3 = template_pointer_cast<B>(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto *b3 = template_pointer_cast<B>(a);
+  B &b4 = template_reference_cast<B>(*a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a);
+  const B *b5 = template_const_pointer_cast<B>(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: const auto *b5 = template_const_pointer_cast<B>(a);
+  const B &b6 = template_const_reference_cast<B>(*a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a);
+  B *b7 = template_value_get<B *>("foo");
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto *b7 = template_value_get<B *>("foo");
+
+  S s;
+  const B *b8 = s.template_member_get<B>();
+
+  auto i2 = template_value_cast<int>(d);
+  int i3 = max(i1, i2);
+}
Index: test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
===================================================================
--- test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
+++ test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
@@ -136,3 +136,64 @@
   B b;
   A a = A(b);
 }
+
+class StringRef
+{
+public:
+  StringRef(const char *);
+};
+
+template <typename T, typename U>
+T template_value_cast(const U &u);
+
+template <typename T, typename U>
+T *template_pointer_cast(U *u);
+
+template <typename T, typename U>
+T &template_reference_cast(U &u);
+
+template <typename T, typename U>
+const T *template_const_pointer_cast(const U *u);
+
+template <typename T, typename U>
+const T &template_const_reference_cast(const U &u);
+
+template <typename T>
+T template_value_get(StringRef s);
+
+template <typename T>
+T max(T t1, T t2);
+
+void f_template_cast()
+{
+  double d = 0;
+  int i1 = template_value_cast<int>(d);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto  i1 = template_value_cast<int>(d);
+
+  A *a = new B();
+  B *b1 = template_value_cast<B *>(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto b1 = template_value_cast<B *>(a);
+  B &b2 = template_value_cast<B &>(*a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto  &b2 = template_value_cast<B &>(*a);
+  B *b3 = template_pointer_cast<B>(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto b3 = template_pointer_cast<B>(a);
+  B &b4 = template_reference_cast<B>(*a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto  &b4 = template_reference_cast<B>(*a);
+  const B *b5 = template_const_pointer_cast<B>(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: const auto b5 = template_const_pointer_cast<B>(a);
+  const B &b6 = template_const_reference_cast<B>(*a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: const auto  &b6 = template_const_reference_cast<B>(*a);
+  B *b7 = template_value_get<B *>("foo");
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto b7 = template_value_get<B *>("foo");
+
+  auto i2 = template_value_cast<int>(d);
+  int i3 = max(i1, i2);
+}
Index: docs/clang-tidy/checks/modernize-use-auto.rst
===================================================================
--- docs/clang-tidy/checks/modernize-use-auto.rst
+++ docs/clang-tidy/checks/modernize-use-auto.rst
@@ -160,7 +160,9 @@
   auto *my_pointer = static_cast<TypeName>(my_param);
 
 The check handles ``static_cast``, ``dynamic_cast``, ``const_cast``,
-``reinterpret_cast``, functional casts and C-style casts.
+``reinterpret_cast``, functional casts, C-style casts and function templates
+that behave as casts, such as ``llvm::dyn_cast``, ``boost::lexical_cast`` and
+``gsl::narrow_cast``.
 
 Known Limitations
 -----------------
@@ -170,9 +172,6 @@
 
 * User-defined iterators are not handled at this time.
 
-* Function templates that behave as casts, such as ``llvm::dyn_cast``,
-  ``boost::lexical_cast`` or ``gsl::narrow_cast`` are not handled.
-
 Options
 -------
 
Index: clang-tidy/modernize/UseAutoCheck.cpp
===================================================================
--- clang-tidy/modernize/UseAutoCheck.cpp
+++ clang-tidy/modernize/UseAutoCheck.cpp
@@ -24,6 +24,7 @@
 const char IteratorDeclStmtId[] = "iterator_decl";
 const char DeclWithNewId[] = "decl_new";
 const char DeclWithCastId[] = "decl_cast";
+const char DeclWithTemplateCastId[] = "decl_template";
 
 /// \brief Matches variable declarations that have explicit initializers that
 /// are not initializer lists.
@@ -169,6 +170,20 @@
   return (Info && Info->isStr("std"));
 }
 
+/// Matches the type that was substituted for the template parameter.
+AST_MATCHER_P(SubstTemplateTypeParmType, hasReplacementType,
+              ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
+  return InnerMatcher.matches(Node.getReplacementType(), Finder, Builder);
+}
+
+/// Matches declaration reference or member expressions with explicit template
+/// arguments.
+AST_POLYMORPHIC_MATCHER(hasExplicitTemplateArgs,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr,
+                                                        MemberExpr)) {
+  return Node.hasExplicitTemplateArgs();
+}
+
 /// \brief Returns a DeclarationMatcher that matches standard iterators nested
 /// inside records with a standard container name.
 DeclarationMatcher standardIterator() {
@@ -240,6 +255,22 @@
       .bind(DeclWithCastId);
 }
 
+StatementMatcher makeDeclWithTemplateCastMatcher() {
+  auto ST =
+      substTemplateTypeParmType(hasReplacementType(equalsBoundNode("arg")));
+
+  return declStmt(
+             unless(has(varDecl(unless(hasInitializer(ignoringImplicit(callExpr(
+                 anyOf(has(memberExpr(hasExplicitTemplateArgs())),
+                       has(ignoringImpCasts(
+                           declRefExpr(hasExplicitTemplateArgs())))),
+                 callee(functionDecl(
+                     hasTemplateArgument(0,
+                                         refersToType(qualType().bind("arg"))),
+                     returns(anyOf(ST, pointsTo(ST), references(ST)))))))))))))
+      .bind(DeclWithTemplateCastId);
+}
+
 StatementMatcher makeCombinedMatcher() {
   return declStmt(
       // At least one varDecl should be a child of the declStmt to ensure
@@ -251,7 +282,7 @@
                                hasType(pointerType(pointee(autoType()))),
                                hasType(referenceType(pointee(autoType()))))))),
       anyOf(makeIteratorDeclMatcher(), makeDeclWithNewMatcher(),
-            makeDeclWithCastMatcher()));
+            makeDeclWithCastMatcher(), makeDeclWithTemplateCastMatcher()));
 }
 
 } // namespace
@@ -411,6 +442,17 @@
         },
         "use auto when initializing with a cast to avoid duplicating the type "
         "name");
+  } else if (const auto *Decl =
+                 Result.Nodes.getNodeAs<DeclStmt>(DeclWithTemplateCastId)) {
+    replaceExpr(
+        Decl, Result.Context,
+        [](const Expr *Expr) {
+          return cast<CallExpr>(Expr->IgnoreImplicit())
+              ->getDirectCallee()
+              ->getReturnType();
+        },
+        "use auto when initializing with a template cast to avoid duplicating "
+        "the type name");
   } else {
     llvm_unreachable("Bad Callback. No node provided.");
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to