[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