malcolm.parsons updated this revision to Diff 73918.
malcolm.parsons added a comment.
Add more tests.
https://reviews.llvm.org/D25316
Files:
clang-tidy/modernize/UseAutoCheck.cpp
clang-tidy/modernize/UseAutoCheck.h
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
test/clang-tidy/modernize-use-auto-new.cpp
Index: test/clang-tidy/modernize-use-auto-new.cpp
===================================================================
--- test/clang-tidy/modernize-use-auto-new.cpp
+++ test/clang-tidy/modernize-use-auto-new.cpp
@@ -15,6 +15,10 @@
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
// CHECK-FIXES: static auto *a_static = new MyType();
+ long long *ll = new long long();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *ll = new long long();
+
MyType *derived = new MyDerivedType();
void *vd = new MyType();
Index: test/clang-tidy/modernize-use-auto-cast.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-auto-cast.cpp
@@ -0,0 +1,113 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- -- \
+// RUN: -std=c++11 -I %S/Inputs/modernize-use-auto
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {};
+
+struct C {};
+
+void f_static_cast() {
+ long l = 1;
+ int i1 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = static_cast<int>(l);
+
+ const int i2 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto i2 = static_cast<int>(l);
+
+ long long ll = static_cast<long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ll = static_cast<long long>(l);
+ unsigned long long ull = static_cast<unsigned long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ull = static_cast<unsigned long long>(l);
+ unsigned int ui = static_cast<unsigned int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ui = static_cast<unsigned int>(l);
+ long double ld = static_cast<long double>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ld = static_cast<long double>(l);
+
+ A *a = new B();
+ B *b1 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = static_cast<B *>(a);
+
+ B *const b2 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *const b2 = static_cast<B *>(a);
+
+ 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: 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
+ // CHECK-FIXES: auto &b4 = static_cast<B &>(*a);
+
+ const B &b5 = 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: const auto &b5 = static_cast<const B &>(*a);
+
+ // Don't warn when auto is already being used.
+ auto i3 = static_cast<int>(l);
+ auto *b6 = static_cast<B *>(a);
+ auto &b7 = static_cast<B &>(*a);
+}
+
+void f_dynamic_cast() {
+ A *a = new B();
+ B *b1 = dynamic_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = dynamic_cast<B *>(a);
+
+ B &b2 = dynamic_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = dynamic_cast<B &>(*a);
+}
+
+void f_reinterpret_cast() {
+ auto *a = new A();
+ C *c1 = reinterpret_cast<C *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *c1 = reinterpret_cast<C *>(a);
+
+ C &c2 = reinterpret_cast<C &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = reinterpret_cast<C &>(*a);
+}
+
+void f_const_cast() {
+ const A *a1 = new A();
+ A *a2 = const_cast<A *>(a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *a2 = const_cast<A *>(a1);
+ A &a3 = const_cast<A &>(*a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &a3 = const_cast<A &>(*a1);
+}
+
+void f_cstyle_cast() {
+ auto *a = new A();
+ C *c1 = (C *)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *c1 = (C *)a;
+
+ C &c2 = (C &)*a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = (C &)*a;
+}
+
+void f_functional_cast() {
+ long l = 1;
+ int i1 = int(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = int(l);
+
+ B b;
+ A a = A(b);
+}
Index: test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
@@ -0,0 +1,114 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'}]}" \
+// RUN: -- -std=c++11
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {};
+
+struct C {};
+
+void f_static_cast() {
+ long l = 1;
+ int i1 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = static_cast<int>(l);
+
+ const int i2 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto i2 = static_cast<int>(l);
+
+ long long ll = static_cast<long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ll = static_cast<long long>(l);
+ unsigned long long ull = static_cast<unsigned long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ull = static_cast<unsigned long long>(l);
+ unsigned int ui = static_cast<unsigned int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ui = static_cast<unsigned int>(l);
+ long double ld = static_cast<long double>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ld = static_cast<long double>(l);
+
+ A *a = new B();
+ B *b1 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = static_cast<B *>(a);
+
+ B *const b2 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto const b2 = static_cast<B *>(a);
+
+ 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);
+
+ 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
+ // CHECK-FIXES: auto &b4 = static_cast<B &>(*a);
+
+ const B &b5 = 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: const auto &b5 = static_cast<const B &>(*a);
+
+ // Don't warn when auto is already being used.
+ auto i3 = static_cast<int>(l);
+ auto *b6 = static_cast<B *>(a);
+ auto &b7 = static_cast<B &>(*a);
+}
+
+void f_dynamic_cast() {
+ A *a = new B();
+ B *b1 = dynamic_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = dynamic_cast<B *>(a);
+
+ B &b2 = dynamic_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = dynamic_cast<B &>(*a);
+}
+
+void f_reinterpret_cast() {
+ auto *a = new A();
+ C *c1 = reinterpret_cast<C *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto c1 = reinterpret_cast<C *>(a);
+
+ C &c2 = reinterpret_cast<C &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = reinterpret_cast<C &>(*a);
+}
+
+void f_const_cast() {
+ const A *a1 = new A();
+ A *a2 = const_cast<A *>(a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto a2 = const_cast<A *>(a1);
+ A &a3 = const_cast<A &>(*a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &a3 = const_cast<A &>(*a1);
+}
+
+void f_cstyle_cast() {
+ auto *a = new A();
+ C *c1 = (C *)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto c1 = (C *)a;
+
+ C &c2 = (C &)*a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = (C &)*a;
+}
+
+void f_functional_cast() {
+ long l = 1;
+ int i1 = int(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = int(l);
+
+ B b;
+ A a = A(b);
+}
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
@@ -143,6 +143,27 @@
auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+Cast expressions
+----------------
+
+Frequently, when a variable is declared and initialized with a cast, the
+variable type has to be written twice: in the declaration type and in the
+cast expression. In this cases, the declaration type can be replaced with
+``auto`` improving readability and maintainability.
+
+.. code-block:: c++
+
+ TypeName *my_pointer = static_cast<TypeName>(my_param);
+
+ // becomes
+
+ 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.
+It does not handle function templates that behave as casts, such as
+``llvm::dyn_cast``, ``boost::lexical_cast`` or ``gsl::narrow_cast``.
+
Known Limitations
-----------------
Index: clang-tidy/modernize/UseAutoCheck.h
===================================================================
--- clang-tidy/modernize/UseAutoCheck.h
+++ clang-tidy/modernize/UseAutoCheck.h
@@ -25,7 +25,9 @@
private:
void replaceIterators(const DeclStmt *D, ASTContext *Context);
- void replaceNew(const DeclStmt *D, ASTContext *Context);
+ template <typename ExprType, typename TypeFn>
+ void replaceExpr(const DeclStmt *D, ASTContext *Context, TypeFn GetType,
+ StringRef message);
const bool RemoveStars;
};
Index: clang-tidy/modernize/UseAutoCheck.cpp
===================================================================
--- clang-tidy/modernize/UseAutoCheck.cpp
+++ clang-tidy/modernize/UseAutoCheck.cpp
@@ -23,6 +23,7 @@
const char IteratorDeclStmtId[] = "iterator_decl";
const char DeclWithNewId[] = "decl_new";
+const char DeclWithCastId[] = "decl_cast";
/// \brief Matches variable declarations that have explicit initializers that
/// are not initializer lists.
@@ -243,6 +244,17 @@
.bind(DeclWithNewId);
}
+StatementMatcher makeDeclWithCastMatcher() {
+ return declStmt(
+ has(varDecl(
+ hasInitializer(explicitCastExpr()),
+ // Skip declarations that are already using auto.
+ unless(anyOf(hasType(autoType()),
+ hasType(pointerType(pointee(autoType()))),
+ hasType(referenceType(pointee(autoType()))))))))
+ .bind(DeclWithCastId);
+}
+
} // namespace
UseAutoCheck::UseAutoCheck(StringRef Name, ClangTidyContext *Context)
@@ -259,6 +271,7 @@
if (getLangOpts().CPlusPlus) {
Finder->addMatcher(makeIteratorDeclMatcher(), this);
Finder->addMatcher(makeDeclWithNewMatcher(), this);
+ Finder->addMatcher(makeDeclWithCastMatcher(), this);
}
}
@@ -313,7 +326,9 @@
<< FixItHint::CreateReplacement(Range, "auto");
}
-void UseAutoCheck::replaceNew(const DeclStmt *D, ASTContext *Context) {
+template <typename ExprType, typename TypeFn>
+void UseAutoCheck::replaceExpr(const DeclStmt *D, ASTContext *Context,
+ TypeFn GetType, StringRef message) {
const auto *FirstDecl = dyn_cast<VarDecl>(*D->decl_begin());
// Ensure that there is at least one VarDecl within the DeclStmt.
if (!FirstDecl)
@@ -328,13 +343,13 @@
if (!V)
return;
- const auto *NewExpr = cast<CXXNewExpr>(V->getInit()->IgnoreParenImpCasts());
- // Ensure that every VarDecl has a CXXNewExpr initializer.
- if (!NewExpr)
+ const auto *Expr = cast<ExprType>(V->getInit()->IgnoreParenImpCasts());
+ // Ensure that every VarDecl has an ExprType initializer.
+ if (!Expr)
return;
// If VarDecl and Initializer have mismatching unqualified types.
- if (!Context->hasSameUnqualifiedType(V->getType(), NewExpr->getType()))
+ if (!Context->hasSameUnqualifiedType(V->getType(), GetType(Expr)))
return;
// All subsequent variables in this declaration should have the same
@@ -368,21 +383,38 @@
Loc = Loc.getNextTypeLoc();
}
SourceRange Range(Loc.getSourceRange());
- auto Diag = diag(Range.getBegin(), "use auto when initializing with new"
- " to avoid duplicating the type name");
+ auto Diag = diag(Range.getBegin(), message);
// Space after 'auto' to handle cases where the '*' in the pointer type is
// next to the identifier. This avoids changing 'int *p' into 'autop'.
- Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto")
+ Diag << FixItHint::CreateReplacement(Range,
+ FirstDeclType->isReferenceType()
+ ? "auto &"
+ : RemoveStars ? "auto " : "auto")
<< StarRemovals;
}
void UseAutoCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *Decl = Result.Nodes.getNodeAs<DeclStmt>(IteratorDeclStmtId)) {
replaceIterators(Decl, Result.Context);
} else if (const auto *Decl =
Result.Nodes.getNodeAs<DeclStmt>(DeclWithNewId)) {
- replaceNew(Decl, Result.Context);
+ auto GetType = [](const CXXNewExpr *Expr) {
+ return Expr->getType();
+ };
+
+ replaceExpr<CXXNewExpr>(Decl, Result.Context, GetType,
+ "use auto when initializing with new to avoid "
+ "duplicating the type name");
+ } else if (const auto *Decl =
+ Result.Nodes.getNodeAs<DeclStmt>(DeclWithCastId)) {
+ auto GetType = [](const ExplicitCastExpr *Expr) {
+ return Expr->getTypeAsWritten();
+ };
+
+ replaceExpr<ExplicitCastExpr>(Decl, Result.Context, GetType,
+ "use auto when initializing with a cast to "
+ "avoid duplicating the type name");
} else {
llvm_unreachable("Bad Callback. No node provided.");
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits