diff --git a/src/lib.rs b/src/lib.rs index 00d28deee..1d760bde9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box len_zero::LenZero as LintPassObject); reg.register_lint_pass(box misc::CmpOwned as LintPassObject); reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); + reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -64,5 +65,6 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_ZERO, len_zero::LEN_WITHOUT_IS_EMPTY, collapsible_if::COLLAPSIBLE_IF, + misc::MODULO_ONE, ]); } diff --git a/src/misc.rs b/src/misc.rs index b8ce6d725..590ebbc3f 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -266,3 +266,34 @@ fn is_str_arg(cx: &Context, args: &[P]) -> bool { args.len() == 1 && if let ty_str = walk_ty(expr_ty(cx.tcx, &*args[0])).sty { true } else { false } } + + +declare_lint!(pub MODULO_ONE, Warn, "Warn on expressions that include % 1, which is always 0"); + +#[derive(Copy,Clone)] +pub struct ModuloOne; + +impl LintPass for ModuloOne { + fn get_lints(&self) -> LintArray { + lint_array!(MODULO_ONE) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, _, ref right) = expr.node { + if let &Spanned {node: BinOp_::BiRem, ..} = cmp { + if is_lit_one(right) { + cx.span_lint(MODULO_ONE, expr.span, "Any number modulo 1 will be 0"); + } + } + } + } +} + +fn is_lit_one(expr: &Expr) -> bool { + if let ExprLit(ref spanned) = expr.node { + if let LitInt(1, _) = spanned.node { + return true; + } + } + false +} diff --git a/tests/compile-fail/modulo_one.rs b/tests/compile-fail/modulo_one.rs new file mode 100644 index 000000000..26c7de855 --- /dev/null +++ b/tests/compile-fail/modulo_one.rs @@ -0,0 +1,8 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(modulo_one)] + +fn main() { + 10 % 1; //~ERROR Any number modulo 1 will be 0 + 10 % 2; +}