diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs new file mode 100644 index 000000000000..7b5b4a3d3afb --- /dev/null +++ b/clippy_lints/src/erasing_op.rs @@ -0,0 +1,62 @@ +use consts::{constant_simple, Constant}; +use rustc::hir::*; +use rustc::lint::*; +use syntax::codemap::Span; +use utils::{in_macro, span_lint}; + +/// **What it does:** Checks for erasing operations, e.g. `x * 0`. +/// +/// **Why is this bad?** The whole expression can be replaced by zero. +/// Most likely mistake was made and code should be reviewed or simplified. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// 0 / x; 0 * x; x & 0 +/// ``` +declare_lint! { + pub ERASING_OP, + Warn, + "using erasing operations, e.g. `x * 0` or `y & 0`" +} + +#[derive(Copy, Clone)] +pub struct ErasingOp; + +impl LintPass for ErasingOp { + fn get_lints(&self) -> LintArray { + lint_array!(ERASING_OP) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ErasingOp { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { + if in_macro(e.span) { + return; + } + if let ExprBinary(ref cmp, ref left, ref right) = e.node { + match cmp.node { + BiMul | BiBitAnd => { + check(cx, left, e.span); + check(cx, right, e.span); + }, + BiDiv => check(cx, left, e.span), + _ => (), + } + } + } +} + +fn check(cx: &LateContext, e: &Expr, span: Span) { + if let Some(Constant::Int(v)) = constant_simple(cx, e) { + if v.to_u128_unchecked() == 0 { + span_lint( + cx, + ERASING_OP, + span, + "the operation is ineffective. Consider reducing it to `0`", + ); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0f27a74ac8e3..6c85b9efa55c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -86,6 +86,7 @@ pub mod entry; pub mod enum_clike; pub mod enum_glob_use; pub mod enum_variants; +pub mod erasing_op; pub mod eq_op; pub mod escape; pub mod eta_reduction; @@ -246,6 +247,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_early_lint_pass(box needless_continue::NeedlessContinue); reg.register_late_lint_pass(box eta_reduction::EtaPass); reg.register_late_lint_pass(box identity_op::IdentityOp); + reg.register_late_lint_pass(box erasing_op::ErasingOp); reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatements); reg.register_late_lint_pass(box mut_mut::MutMut); reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); diff --git a/tests/ui/bit_masks.stderr b/tests/ui/bit_masks.stderr index 9f2c2d0a2c4a..45b8bbe6d9e4 100644 --- a/tests/ui/bit_masks.stderr +++ b/tests/ui/bit_masks.stderr @@ -6,6 +6,14 @@ error: &-masking with zero | = note: `-D bad-bit-mask` implied by `-D warnings` +error: the operation is ineffective. Consider reducing it to `0` + --> $DIR/bit_masks.rs:12:5 + | +12 | x & 0 == 0; + | ^^^^^ + | + = note: `-D erasing-op` implied by `-D warnings` + error: incompatible bit mask: `_ & 2` can never be equal to `1` --> $DIR/bit_masks.rs:15:5 | @@ -48,6 +56,12 @@ error: &-masking with zero 35 | 0 & x == 0; | ^^^^^^^^^^ +error: the operation is ineffective. Consider reducing it to `0` + --> $DIR/bit_masks.rs:35:5 + | +35 | 0 & x == 0; + | ^^^^^ + error: incompatible bit mask: `_ | 2` will always be higher than `1` --> $DIR/bit_masks.rs:39:5 | diff --git a/tests/ui/erasing_op.rs b/tests/ui/erasing_op.rs new file mode 100644 index 000000000000..e5143146f266 --- /dev/null +++ b/tests/ui/erasing_op.rs @@ -0,0 +1,12 @@ + + + +#[allow(no_effect)] +#[warn(erasing_op)] +fn main() { + let x: u8 = 0; + + x * 0; + 0 & x; + 0 / x; +} diff --git a/tests/ui/erasing_op.stderr b/tests/ui/erasing_op.stderr new file mode 100644 index 000000000000..496c297ef2b4 --- /dev/null +++ b/tests/ui/erasing_op.stderr @@ -0,0 +1,20 @@ +error: the operation is ineffective. Consider reducing it to `0` + --> $DIR/erasing_op.rs:9:5 + | +9 | x * 0; + | ^^^^^ + | + = note: `-D erasing-op` implied by `-D warnings` + +error: the operation is ineffective. Consider reducing it to `0` + --> $DIR/erasing_op.rs:10:5 + | +10 | 0 & x; + | ^^^^^ + +error: the operation is ineffective. Consider reducing it to `0` + --> $DIR/erasing_op.rs:11:5 + | +11 | 0 / x; + | ^^^^^ +