Merge pull request #204 from Manishearth/bit-mask

Extend and correct the ineffective_bit_mask check
This commit is contained in:
llogiq 2015-08-19 13:25:43 +02:00
commit 150840667e
2 changed files with 37 additions and 14 deletions

View file

@ -39,7 +39,13 @@ declare_lint! {
/// This lint is **deny** by default
///
/// There is also a lint that warns on ineffective masks that is *warn*
/// by default
/// by default.
///
/// |Comparison|Bit-Op |Example |equals |Formula|
/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`|
/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` |
///
/// `¹ power_of_two(c + 1)`
#[derive(Copy,Clone)]
pub struct BitMask;
@ -127,12 +133,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
"incompatible bit mask: `_ | {}` will never be lower than `{}`",
mask_value, cmp_value));
} else {
if mask_value < cmp_value {
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
"ineffective bit mask: `x | {}` compared to `{}` is the same as x compared directly",
mask_value, cmp_value));
}
check_ineffective_lt(cx, *span, mask_value, cmp_value, "|");
},
BiBitXor =>
check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"),
_ => ()
},
BiLe | BiGt => match bit_op {
@ -151,18 +155,32 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_,
"incompatible bit mask: `_ | {}` will always be higher than `{}`",
mask_value, cmp_value));
} else {
if mask_value < cmp_value {
span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!(
"ineffective bit mask: `x | {}` compared to `{}` is the same as x compared directly",
mask_value, cmp_value));
}
check_ineffective_gt(cx, *span, mask_value, cmp_value, "|");
},
BiBitXor =>
check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"),
_ => ()
},
_ => ()
}
}
fn check_ineffective_lt(cx: &Context, span: Span, m: u64, c: u64, op: &str) {
if c.is_power_of_two() && m < c {
span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!(
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
op, m, c));
}
}
fn check_ineffective_gt(cx: &Context, span: Span, m: u64, c: u64, op: &str) {
if (c + 1).is_power_of_two() && m <= c {
span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!(
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
op, m, c));
}
}
fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> {
match &lit.node {
&ExprLit(ref lit_ptr) => {

View file

@ -46,8 +46,13 @@ fn main() {
fn ineffective() {
let x = 5;
x | 1 > 2; //~ERROR ineffective bit mask
x | 1 < 3; //~ERROR ineffective bit mask
x | 1 > 3; //~ERROR ineffective bit mask
x | 1 < 4; //~ERROR ineffective bit mask
x | 1 <= 3; //~ERROR ineffective bit mask
x | 1 >= 2; //~ERROR ineffective bit mask
x | 1 >= 8; //~ERROR ineffective bit mask
x | 1 > 2; // not an error (yet), better written as x >= 2
x | 1 >= 7; // not an error (yet), better written as x >= 6
x | 3 > 4; // not an error (yet), better written as x >= 4
x | 4 <= 19;
}