From 7102442a4b2f1d877bdd62ab93a4332496791183 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 3 Jul 2017 16:07:04 +0200 Subject: [PATCH] Use the authoring tool to create a new lint --- clippy_lints/src/bit_mask.rs | 42 ++++++++++++++++++++- clippy_lints/src/lib.rs | 1 + clippy_tests/examples/bit_masks.stderr | 16 +++++++- clippy_tests/examples/trailing_zeros.stderr | 18 +++++++++ clippy_tests/examples/trailing_zeros.stdout | 4 +- 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index c1fbd33b2a5..889f74d52e7 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -4,7 +4,8 @@ use rustc_const_eval::lookup_const_by_id; use syntax::ast::LitKind; use syntax::codemap::Span; -use utils::span_lint; +use utils::{span_lint, span_lint_and_then}; +use utils::sugg::Sugg; /// **What it does:** Checks for incompatible bit masks in comparisons. /// @@ -70,12 +71,29 @@ "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`" } +/// **What it does:** Checks for bit masks that can be replaced by a call +/// to `trailing_zeros` +/// +/// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15 == 0` +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// x & 0x1111 == 0 +/// ``` +declare_lint! { + pub VERBOSE_BIT_MASK, + Warn, + "expressions where a bit mask is less readable than the corresponding method call" +} + #[derive(Copy,Clone)] pub struct BitMask; impl LintPass for BitMask { fn get_lints(&self) -> LintArray { - lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK) + lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK) } } @@ -90,6 +108,26 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { } } } + if_let_chain!{[ + let Expr_::ExprBinary(ref op, ref left, ref right) = e.node, + BinOp_::BiEq == op.node, + let Expr_::ExprBinary(ref op1, ref left1, ref right1) = left.node, + BinOp_::BiBitAnd == op1.node, + let Expr_::ExprLit(ref lit) = right1.node, + let LitKind::Int(n, _) = lit.node, + let Expr_::ExprLit(ref lit1) = right.node, + let LitKind::Int(0, _) = lit1.node, + n.leading_zeros() == n.count_zeros(), + ], { + span_lint_and_then(cx, + VERBOSE_BIT_MASK, + e.span, + "bit mask could be simplified with a call to `trailing_zeros`", + |db| { + let sugg = Sugg::hir(cx, left1, "...").maybe_par(); + db.span_suggestion(e.span, "try", format!("{}.trailing_zeros() > {}", sugg, n.count_ones())); + }); + }} } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f1998235d30..0c1c14f5b8c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -380,6 +380,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { attrs::USELESS_ATTRIBUTE, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, + bit_mask::VERBOSE_BIT_MASK, blacklisted_name::BLACKLISTED_NAME, block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, diff --git a/clippy_tests/examples/bit_masks.stderr b/clippy_tests/examples/bit_masks.stderr index 38a68b2831b..64f5e0f2045 100644 --- a/clippy_tests/examples/bit_masks.stderr +++ b/clippy_tests/examples/bit_masks.stderr @@ -6,6 +6,20 @@ error: &-masking with zero | = note: `-D bad-bit-mask` implied by `-D warnings` +error: bit mask could be simplified with a call to `trailing_zeros` + --> bit_masks.rs:12:5 + | +12 | x & 0 == 0; + | ^^^^^^^^^^ help: try `x.trailing_zeros() > 0` + | + = note: `-D verbose-bit-mask` implied by `-D warnings` + +error: bit mask could be simplified with a call to `trailing_zeros` + --> bit_masks.rs:14:5 + | +14 | x & 1 == 0; //ok, compared with zero + | ^^^^^^^^^^ help: try `x.trailing_zeros() > 1` + error: incompatible bit mask: `_ & 2` can never be equal to `1` --> bit_masks.rs:15:5 | @@ -92,7 +106,7 @@ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared 55 | x | 1 >= 8; | ^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors To learn more, run the command again with --verbose. diff --git a/clippy_tests/examples/trailing_zeros.stderr b/clippy_tests/examples/trailing_zeros.stderr index e69de29bb2d..4fb608c7bf1 100644 --- a/clippy_tests/examples/trailing_zeros.stderr +++ b/clippy_tests/examples/trailing_zeros.stderr @@ -0,0 +1,18 @@ +error: bit mask could be simplified with a call to `trailing_zeros` + --> trailing_zeros.rs:7:31 + | +7 | let _ = #[clippy(author)] (x & 0b1111 == 0); // suggest trailing_zeros + | ^^^^^^^^^^^^^^^^^ help: try `x.trailing_zeros() > 4` + | + = note: `-D verbose-bit-mask` implied by `-D warnings` + +error: bit mask could be simplified with a call to `trailing_zeros` + --> trailing_zeros.rs:8:13 + | +8 | let _ = x & 0b11111 == 0; // suggest trailing_zeros + | ^^^^^^^^^^^^^^^^ help: try `x.trailing_zeros() > 5` + +error: aborting due to 2 previous errors + + +To learn more, run the command again with --verbose. diff --git a/clippy_tests/examples/trailing_zeros.stdout b/clippy_tests/examples/trailing_zeros.stdout index 7f1e8a60096..98025316da4 100644 --- a/clippy_tests/examples/trailing_zeros.stdout +++ b/clippy_tests/examples/trailing_zeros.stdout @@ -9,6 +9,6 @@ if_let_chain!{[ let LitKind::Int(15, _) = lit.node, let Expr_::ExprLit(ref lit1) = right.node, let LitKind::Int(0, _) = lit1.node, -]} { +], { // report your lint here -} +}} -- 2.44.0