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:
llogiq 2015-05-04 07:17:15 +02:00
parent 53fa76dff9
commit 07adeee6e9
6 changed files with 130 additions and 4 deletions

View file

@ -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,

View file

@ -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
]);
}

View file

@ -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
View 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 &[...]");
}
}

View file

@ -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
}

View 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);
}