Added 'ineffective bit mask' lint

This commit is contained in:
llogiq 2015-05-15 14:09:29 +02:00
parent 905509083c
commit 6bec4f35df
4 changed files with 50 additions and 10 deletions

View File

@ -13,6 +13,7 @@ Lints included in this crate:
- `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`)
- `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination
- `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have)
- `ineffective_bit_mask`: Warns on expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`
- `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
- `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively
- `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant

View File

@ -32,12 +32,18 @@ declare_lint! {
"Deny the use of incompatible bit masks in comparisons, e.g. '(a & 1) == 2'"
}
declare_lint! {
pub INEFFECTIVE_BIT_MASK,
Warn,
"Warn on the use of an ineffective bit mask in comparisons, e.g. '(a & 1) > 2'"
}
#[derive(Copy,Clone)]
pub struct BitMask;
impl LintPass for BitMask {
fn get_lints(&self) -> LintArray {
lint_array!(BAD_BIT_MASK)
lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK)
}
fn check_expr(&mut self, cx: &Context, e: &Expr) {
@ -102,31 +108,47 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64,
},
BiLt | BiGe => match bit_op {
BiBitAnd => if mask_value < cmp_value {
cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will always be lower than {}", mask_value,
cmp_value));
cx.span_lint(BAD_BIT_MASK, *span, &format!(
"incompatible bit mask: _ & {} will always be lower than {}",
mask_value, cmp_value));
} else {
if mask_value == 0 {
cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
}
},
BiBitOr => if mask_value >= cmp_value {
cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will never be lower than {}", mask_value,
cmp_value));
cx.span_lint(BAD_BIT_MASK, *span, &format!(
"incompatible bit mask: _ | {} will never be lower than {}",
mask_value, cmp_value));
} else {
if mask_value < cmp_value {
cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
mask_value, cmp_value));
}
},
_ => ()
},
BiLe | BiGt => match bit_op {
BiBitAnd => if mask_value <= cmp_value {
cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will never be higher than {}", mask_value,
cmp_value));
cx.span_lint(BAD_BIT_MASK, *span, &format!(
"incompatible bit mask: _ & {} will never be higher than {}",
mask_value, cmp_value));
} else {
if mask_value == 0 {
cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
}
},
BiBitOr => if mask_value > cmp_value {
cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will always be higher than {}", mask_value,
cmp_value));
cx.span_lint(BAD_BIT_MASK, *span, &format!(
"incompatible bit mask: _ | {} will always be higher than {}",
mask_value, cmp_value));
} else {
if mask_value < cmp_value {
cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
mask_value, cmp_value));
}
},
_ => ()
},

View File

@ -42,7 +42,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST,
misc::SINGLE_MATCH, misc::STR_TO_STRING,
misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP,
bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG,
bit_mask::BAD_BIT_MASK,
bit_mask::INEFFECTIVE_BIT_MASK,
ptr_arg::PTR_ARG,
needless_bool::NEEDLESS_BOOL,
approx_const::APPROX_CONSTANT,
misc::CMP_NAN, misc::FLOAT_CMP,

View File

@ -5,6 +5,7 @@ const THREE_BITS : i64 = 7;
const EVEN_MORE_REDIRECTION : i64 = THREE_BITS;
#[deny(bad_bit_mask)]
#[allow(ineffective_bit_mask)]
fn main() {
let x = 5;
@ -34,4 +35,18 @@ fn main() {
1 < 2 | x; //~ERROR
2 == 3 | x; //~ERROR
1 == x & 2; //~ERROR
x | 1 > 2; // no error, because we allowed ineffective bit masks
ineffective();
}
#[deny(ineffective_bit_mask)]
#[allow(bad_bit_mask)]
fn ineffective() {
let x = 5;
x | 1 > 2; //~ERROR
x | 1 < 3; //~ERROR
x | 1 <= 3; //~ERROR
x | 1 >= 2; //~ERROR
}