mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 23:24:24 +00:00
Added check for zero bitmask and uncommon directions, wrong comment in needless_bool corrected, added new lint vec_ptr_arg + test
This commit is contained in:
parent
53fa76dff9
commit
07adeee6e9
6 changed files with 130 additions and 4 deletions
|
@ -43,12 +43,31 @@ impl LintPass for BitMask {
|
|||
fn check_expr(&mut self, cx: &Context, e: &Expr) {
|
||||
if let ExprBinary(ref cmp, ref left, ref right) = e.node {
|
||||
if is_comparison_binop(cmp.node) {
|
||||
fetch_int_literal(cx, right).map(|cmp_value| check_compare(cx, left, cmp.node, cmp_value, &e.span));
|
||||
let cmp_opt = fetch_int_literal(cx, right);
|
||||
if cmp_opt.is_some() {
|
||||
check_compare(cx, left, cmp.node, cmp_opt.unwrap(), &e.span);
|
||||
} else {
|
||||
fetch_int_literal(cx, left).map(|cmp_val|
|
||||
check_compare(cx, right, invert_cmp(cmp.node), cmp_val, &e.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn invert_cmp(cmp : BinOp_) -> BinOp_ {
|
||||
match cmp {
|
||||
BiEq => BiEq,
|
||||
BiNe => BiNe,
|
||||
BiLt => BiGt,
|
||||
BiGt => BiLt,
|
||||
BiLe => BiGe,
|
||||
BiGe => BiLe,
|
||||
_ => BiOr // Dummy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
|
||||
match &bit_op.node {
|
||||
&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
|
||||
|
@ -70,6 +89,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64,
|
|||
BiBitAnd => if mask_value & cmp_value != mask_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", 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 != cmp_value {
|
||||
cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value,
|
||||
|
@ -81,6 +104,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64,
|
|||
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));
|
||||
} 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,
|
||||
|
@ -92,6 +119,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64,
|
|||
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));
|
||||
} 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,
|
||||
|
|
|
@ -19,6 +19,7 @@ pub mod misc;
|
|||
pub mod eq_op;
|
||||
pub mod bit_mask;
|
||||
pub mod needless_bool;
|
||||
pub mod vec_ptr_arg;
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
|
@ -29,9 +30,13 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||
reg.register_lint_pass(box eq_op::EqOp as LintPassObject);
|
||||
reg.register_lint_pass(box bit_mask::BitMask as LintPassObject);
|
||||
reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject);
|
||||
reg.register_lint_pass(box vec_ptr_arg::VecPtrArg as LintPassObject);
|
||||
|
||||
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,
|
||||
needless_bool::NEEDLESS_BOOL]);
|
||||
needless_bool::NEEDLESS_BOOL,
|
||||
vec_ptr_arg::VEC_PTR_ARG
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Checks for needless boolean results of if-else expressions
|
||||
//!
|
||||
//! This lint is **deny** by default
|
||||
//! This lint is **warn** by default
|
||||
|
||||
use rustc::plugin::Registry;
|
||||
use rustc::lint::*;
|
||||
|
|
65
src/vec_ptr_arg.rs
Normal file
65
src/vec_ptr_arg.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
//! Checks for usage of &Vec[_] and &String
|
||||
//!
|
||||
//! This lint is **warn** by default
|
||||
|
||||
use rustc::plugin::Registry;
|
||||
use rustc::lint::*;
|
||||
use rustc::middle::const_eval::lookup_const_by_id;
|
||||
use rustc::middle::def::*;
|
||||
use syntax::ast::*;
|
||||
use syntax::ast_util::{is_comparison_binop, binop_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::codemap::Span;
|
||||
use types::match_ty_unwrap;
|
||||
|
||||
declare_lint! {
|
||||
pub VEC_PTR_ARG,
|
||||
Allow,
|
||||
"Warn on declaration of a &Vec-typed method argument"
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy,Clone)]
|
||||
pub struct VecPtrArg;
|
||||
|
||||
impl LintPass for VecPtrArg {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(VEC_PTR_ARG)
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &Context, item: &Item) {
|
||||
if let &ItemFn(ref decl, _, _, _, _) = &item.node {
|
||||
check_fn(cx, decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) {
|
||||
if let &MethodImplItem(ref sig, _) = &item.node {
|
||||
check_fn(cx, &sig.decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) {
|
||||
if let &MethodTraitItem(ref sig, _) = &item.node {
|
||||
check_fn(cx, &sig.decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(cx: &Context, decl: &FnDecl) {
|
||||
for arg in &decl.inputs {
|
||||
let ty = &arg.ty;
|
||||
match ty.node {
|
||||
TyPtr(ref pty) => check_ptr_subtype(cx, ty.span, &pty.ty),
|
||||
TyRptr(_, ref rpty) => check_ptr_subtype(cx, ty.span, &rpty.ty),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) {
|
||||
if match_ty_unwrap(ty, &["Vec"]).is_some() {
|
||||
cx.span_lint(VEC_PTR_ARG, span,
|
||||
"Writing '&Vec<_>' instead of '&[_]' involves one more reference and cannot be used with non-vec-based slices. Consider changing the type to &[...]");
|
||||
}
|
||||
}
|
|
@ -7,12 +7,15 @@ const EVEN_MORE_REDIRECTION : i64 = THREE_BITS;
|
|||
#[deny(bad_bit_mask)]
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
||||
x & 0 == 0; //~ERROR &-masking with zero
|
||||
x & 1 == 1; //ok, distinguishes bit 0
|
||||
x & 2 == 1; //~ERROR
|
||||
x | 0 == 0; //ok, equals x == 0 (maybe warn?)
|
||||
x | 1 == 3; //ok, equals x == 2 || x == 3
|
||||
x | 3 == 3; //ok, equals x <= 3
|
||||
x | 3 == 2; //~ERROR
|
||||
|
||||
|
||||
x & 1 > 1; //~ERROR
|
||||
x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
|
||||
x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0
|
||||
|
@ -23,4 +26,12 @@ fn main() {
|
|||
// this also now works with constants
|
||||
x & THREE_BITS == 8; //~ERROR
|
||||
x | EVEN_MORE_REDIRECTION < 7; //~ERROR
|
||||
|
||||
0 & x == 0; //~ERROR
|
||||
1 | x > 1;
|
||||
|
||||
// and should now also match uncommon usage
|
||||
1 < 2 | x; //~ERROR
|
||||
2 == 3 | x; //~ERROR
|
||||
1 == x & 2; //~ERROR
|
||||
}
|
||||
|
|
14
tests/compile-fail/vec_ptr_arg.rs
Normal file
14
tests/compile-fail/vec_ptr_arg.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
#![feature(plugin)]
|
||||
#![plugin(clippy)]
|
||||
|
||||
#[deny(vec_ptr_arg)]
|
||||
#[allow(unused)]
|
||||
fn go(x: &Vec<i64>) { //~ERROR: Writing '&Vec<_>' instead of '&[_]'
|
||||
//Nothing here
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let x = vec![1i64, 2, 3];
|
||||
go(&x);
|
||||
}
|
Loading…
Reference in a new issue