[clang-tools-extra] r289797 - [clang-tidy] Enhance modernize-use-auto to templated function casts

Malcolm Parsons via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 15 02:19:57 PST 2016


Author: malcolm.parsons
Date: Thu Dec 15 04:19:56 2016
New Revision: 289797

URL: http://llvm.org/viewvc/llvm-project?rev=289797&view=rev
Log:
[clang-tidy] Enhance modernize-use-auto to templated function casts

Summary:
Use auto when declaring variables that are initialized by calling a templated
function that returns its explicit first argument.

Fixes PR26763.

Reviewers: aaron.ballman, alexfh, staronj, Prazek

Subscribers: Eugene.Zelenko, JDevlieghere, cfe-commits

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

Modified:
    clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp
    clang-tools-extra/trunk/docs/ReleaseNotes.rst
    clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst
    clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
    clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp

Modified: clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp?rev=289797&r1=289796&r2=289797&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/modernize/UseAutoCheck.cpp Thu Dec 15 04:19:56 2016
@@ -24,6 +24,7 @@ namespace {
 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,14 @@ AST_MATCHER(Decl, isFromStdNamespace) {
   return (Info && Info->isStr("std"));
 }
 
+/// 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,18 +249,38 @@ StatementMatcher makeDeclWithCastMatcher
       .bind(DeclWithCastId);
 }
 
+StatementMatcher makeDeclWithTemplateCastMatcher() {
+  auto ST =
+      substTemplateTypeParmType(hasReplacementType(equalsBoundNode("arg")));
+
+  auto ExplicitCall =
+      anyOf(has(memberExpr(hasExplicitTemplateArgs())),
+            has(ignoringImpCasts(declRefExpr(hasExplicitTemplateArgs()))));
+
+  auto TemplateArg =
+      hasTemplateArgument(0, refersToType(qualType().bind("arg")));
+
+  auto TemplateCall = callExpr(
+      ExplicitCall,
+      callee(functionDecl(TemplateArg,
+                          returns(anyOf(ST, pointsTo(ST), references(ST))))));
+
+  return declStmt(unless(has(varDecl(
+                      unless(hasInitializer(ignoringImplicit(TemplateCall)))))))
+      .bind(DeclWithTemplateCastId);
+}
+
 StatementMatcher makeCombinedMatcher() {
   return declStmt(
       // At least one varDecl should be a child of the declStmt to ensure
       // it's a declaration list and avoid matching other declarations,
       // e.g. using directives.
-      has(varDecl()),
+      has(varDecl(unless(isImplicit()))),
       // Skip declarations that are already using auto.
       unless(has(varDecl(anyOf(hasType(autoType()),
-                               hasType(pointerType(pointee(autoType()))),
-                               hasType(referenceType(pointee(autoType()))))))),
+                               hasType(qualType(hasDescendant(autoType()))))))),
       anyOf(makeIteratorDeclMatcher(), makeDeclWithNewMatcher(),
-            makeDeclWithCastMatcher()));
+            makeDeclWithCastMatcher(), makeDeclWithTemplateCastMatcher()));
 }
 
 } // namespace
@@ -389,6 +418,8 @@ void UseAutoCheck::replaceExpr(const Dec
 
   // Space after 'auto' to handle cases where the '*' in the pointer type is
   // next to the identifier. This avoids changing 'int *p' into 'autop'.
+  // FIXME: This doesn't work for function pointers because the variable name
+  // is inside the type.
   Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto")
        << StarRemovals;
 }
@@ -411,6 +442,17 @@ void UseAutoCheck::check(const MatchFind
         },
         "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.");
   }

Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=289797&r1=289796&r2=289797&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Thu Dec 15 04:19:56 2016
@@ -93,7 +93,8 @@ Improvements to clang-tidy
 
 - The `modernize-use-auto
   <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-auto.html>`_ check
-  now warns about variable declarations that are initialized with a cast.
+  now warns about variable declarations that are initialized with a cast, or by
+  calling a templated function that behaves as a cast.
 
 - The modernize-use-default check has been renamed to `modernize-use-equals-default
   <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-default.html>`_.

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst?rev=289797&r1=289796&r2=289797&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-auto.rst Thu Dec 15 04:19:56 2016
@@ -160,7 +160,11 @@ cast expression. In this cases, the decl
   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``.  Calls to function templates are considered to behave as
+casts if the first template argument is explicit and is a type, and the function
+returns that type, or a pointer or reference to it.
 
 Known Limitations
 -----------------
@@ -170,9 +174,6 @@ Known Limitations
 
 * 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
 -------
 

Modified: clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp?rev=289797&r1=289796&r2=289797&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp Thu Dec 15 04:19:56 2016
@@ -44,7 +44,7 @@ void f_static_cast() {
 
   const B *b3 = static_cast<const B *>(a);
   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
-  // CHECK-FIXES: auto b3 = static_cast<const B *>(a);
+  // CHECK-FIXES: const auto b3 = static_cast<const B *>(a);
 
   B &b4 = static_cast<B &>(*a);
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
@@ -58,6 +58,9 @@ void f_static_cast() {
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
   // CHECK-FIXES: auto  &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
 
+  // Don't warn when non-cast involved
+  long double cast = static_cast<long double>(l), noncast = 5;
+
   // Don't warn when auto is already being used.
   auto i3 = static_cast<int>(l);
   auto *b8 = static_cast<B *>(a);
@@ -136,3 +139,95 @@ void f_functional_cast() {
   B b;
   A a = A(b);
 }
+
+class StringRef
+{
+public:
+  StringRef(const char *);
+  const char *begin() const;
+  const char *end() const;
+};
+
+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");
+  B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto b8 = template_value_get<B *>("foo"), b9 = template_value_get<B *>("bar");
+
+  S s;
+  const B *b10 = s.template_member_get<B>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: const auto b10 = s.template_member_get<B>();
+
+  // Don't warn when auto is already being used.
+  auto i2 = template_value_cast<int>(d);
+  auto *i3 = template_value_cast<int *>(d);
+  auto **i4 = template_value_cast<int **>(d);
+  auto &i5 = template_reference_cast<int>(d);
+
+  // Don't warn for implicit template arguments.
+  int i6 = max(i1, i2);
+
+  // Don't warn for mismatched var and initializer types.
+  A *a1 = template_value_cast<B *>(a);
+
+  // Don't warn for mismatched var types.
+  B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar");
+
+  // Don't warn for implicit variables.
+  for (auto &c : template_reference_cast<StringRef>(*a)) {
+  }
+}

Modified: clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp?rev=289797&r1=289796&r2=289797&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-auto-cast.cpp Thu Dec 15 04:19:56 2016
@@ -138,3 +138,95 @@ void f_functional_cast() {
   B b;
   A a = A(b);
 }
+
+class StringRef
+{
+public:
+  StringRef(const char *);
+  const char *begin() const;
+  const char *end() const;
+};
+
+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");
+  B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: auto *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+
+  S s;
+  const B *b10 = s.template_member_get<B>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+  // CHECK-FIXES: const auto *b10 = s.template_member_get<B>();
+
+  // Don't warn when auto is already being used.
+  auto i2 = template_value_cast<int>(d);
+  auto *i3 = template_value_cast<int *>(d);
+  auto **i4 = template_value_cast<int **>(d);
+  auto &i5 = template_reference_cast<int>(d);
+
+  // Don't warn for implicit template arguments.
+  int i6 = max(i1, i2);
+
+  // Don't warn for mismatched var and initializer types.
+  A *a1 = template_value_cast<B *>(a);
+
+  // Don't warn for mismatched var types.
+  B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar");
+
+  // Don't warn for implicit variables.
+  for (auto &c : template_reference_cast<StringRef>(*a)) {
+  }
+}




More information about the cfe-commits mailing list