diff --git a/CHANGELOG.md b/CHANGELOG.md index 1192195cd6a5..fd29dd896012 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -447,6 +447,7 @@ All notable changes to this project will be documented in this file. [`type_complexity`]: https://github.com/Manishearth/rust-clippy/wiki#type_complexity [`unicode_not_nfc`]: https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc [`unit_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#unit_cmp +[`unnecessary_cast`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_cast [`unnecessary_mut_passed`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed [`unnecessary_operation`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation [`unneeded_field_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern diff --git a/README.md b/README.md index 842e654678b8..6c11c8e53eca 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,7 @@ name [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types that might be better factored into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values +[unnecessary_cast](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_cast) | warn | cast to the same type, e.g `x as i32` where `x: i32` [unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument passed as a mutable reference although the callee only demands an immutable reference [unnecessary_operation](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation) | warn | outer expressions with no effect [unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | struct fields bound to a wildcard instead of using `..` diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 814daf7d6458..a755ed684073 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -497,6 +497,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { types::LINKEDLIST, types::TYPE_COMPLEXITY, types::UNIT_CMP, + types::UNNECESSARY_CAST, unicode::ZERO_WIDTH_SPACE, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_io_amount::UNUSED_IO_AMOUNT, diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index b1581127c325..17d4ebd87081 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -379,6 +379,22 @@ declare_lint! { and `x > i32::MAX`" } +/// **What it does:** Checks for casts to the same type. +/// +/// **Why is this bad?** It's just unnecessary. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let _ = 2i32 as i32 +/// ``` +declare_lint! { + pub UNNECESSARY_CAST, + Warn, + "cast to the same type, e.g `x as i32` where `x: i32`" +} + /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant fn int_ty_to_nbits(typ: &ty::TyS) -> usize { @@ -503,7 +519,8 @@ impl LintPass for CastPass { lint_array!(CAST_PRECISION_LOSS, CAST_SIGN_LOSS, CAST_POSSIBLE_TRUNCATION, - CAST_POSSIBLE_WRAP) + CAST_POSSIBLE_WRAP, + UNNECESSARY_CAST) } } @@ -511,6 +528,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprCast(ref ex, _) = expr.node { let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr)); + if let ExprLit(ref lit) = ex.node { + use syntax::ast::{LitKind, LitIntType}; + match lit.node { + LitKind::Int(_, LitIntType::Unsuffixed) | + LitKind::FloatUnsuffixed(_) => {}, + _ => { + if cast_from.sty == cast_to.sty && !in_external_macro(cx, expr.span) { + span_lint(cx, + UNNECESSARY_CAST, + expr.span, + &format!("casting to the same type is unnecessary (`{}` -> `{}`)", + cast_from, + cast_to)); + } + }, + } + } if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index ca5106102e9c..d63e0b102787 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -61,4 +61,17 @@ fn main() { 1u32 as usize; // Should not trigger any lint 1i32 as isize; // Neither should this 1i32 as usize; + + // Test cast_unnecessary + 1i32 as i32; + 1f32 as f32; + false as bool; + &1i32 as &i32; + + // Should not trigger + 1i32 as i64; + let v = vec!(1); + &v as &[i32]; + 1.0 as f64; + 1 as u64; } diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index f4d8ec21d8d9..7238daa2b411 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -274,5 +274,29 @@ error: casting i32 to usize may lose the sign of the value 63 | 1i32 as usize; | ^^^^^^^^^^^^^ +warning: casting to the same type is unnecessary (`i32` -> `i32`) + --> $DIR/cast.rs:66:5 + | +66 | 1i32 as i32; + | ^^^^^^^^^^^ + | + = note: #[warn(unnecessary_cast)] on by default + +warning: casting to the same type is unnecessary (`f32` -> `f32`) + --> $DIR/cast.rs:67:5 + | +67 | 1f32 as f32; + | ^^^^^^^^^^^ + | + = note: #[warn(unnecessary_cast)] on by default + +warning: casting to the same type is unnecessary (`bool` -> `bool`) + --> $DIR/cast.rs:68:5 + | +68 | false as bool; + | ^^^^^^^^^^^^^ + | + = note: #[warn(unnecessary_cast)] on by default + error: aborting due to 42 previous errors