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.
///
"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)
}
}
}
}
}
+ 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()));
+ });
+ }}
}
}
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,
|
= 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
|
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.
+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.