From 96bfade4f13af23f95c7381a3b08168f9e852f99 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 18 May 2015 09:02:24 +0200 Subject: [PATCH] New lint: mut_mut (closes issue #9) --- README.md | 1 + src/lib.rs | 3 +++ src/mut_mut.rs | 51 +++++++++++++++++++++++++++++++++++ tests/compile-fail/mut_mut.rs | 20 ++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 src/mut_mut.rs create mode 100644 tests/compile-fail/mut_mut.rs diff --git a/README.md b/README.md index 47747d86e..ddc28a95f 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Lints included in this crate: - `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` - `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`) - `identity_op`: Warns on identity operations like `x + 0` or `y / 1` (which can be reduced to `x` and `y`, respectively) + - `mut_mut`: Warns on `&mut &mut` which is either a copy'n'paste error, or shows a fundamental misunderstanding of references To use, add the following lines to your Cargo.toml: diff --git a/src/lib.rs b/src/lib.rs index c9585d2eb..cd918bff4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ pub mod needless_bool; pub mod approx_const; pub mod eta_reduction; pub mod identity_op; +pub mod mut_mut; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -40,6 +41,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::Precedence as LintPassObject); reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); + reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -53,5 +55,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::PRECEDENCE, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, + mut_mut::MUT_MUT, ]); } diff --git a/src/mut_mut.rs b/src/mut_mut.rs new file mode 100644 index 000000000..0a58e2939 --- /dev/null +++ b/src/mut_mut.rs @@ -0,0 +1,51 @@ +use syntax::ptr::P; +use syntax::ast; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::visit::{FnKind}; +use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; +use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; +use syntax::codemap::{Span, Spanned}; + +declare_lint!(pub MUT_MUT, Warn, + "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); + +#[derive(Copy,Clone)] +pub struct MutMut; + +impl LintPass for MutMut { + fn get_lints(&self) -> LintArray { + lint_array!(MUT_MUT) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + + fn unwrap_addr(expr : &Expr) -> Option<&Expr> { + match expr.node { + ExprAddrOf(MutMutable, ref e) => Option::Some(e), + _ => Option::None + } + } + + if unwrap_addr(expr).and_then(unwrap_addr).is_some() { + cx.span_lint(MUT_MUT, expr.span, + "We're not sure what this means, so if you know, please tell us.") + } + } + + fn check_ty(&mut self, cx: &Context, ty: &Ty) { + + fn unwrap_mut(ty : &Ty) -> Option<&Ty> { + match ty.node { + TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + _ => Option::None + } + } + + if unwrap_mut(ty).and_then(unwrap_mut).is_some() { + cx.span_lint(MUT_MUT, ty.span, + "We're not sure what this means, so if you know, please tell us.") + } + } +} diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs new file mode 100644 index 000000000..7d1dad44a --- /dev/null +++ b/tests/compile-fail/mut_mut.rs @@ -0,0 +1,20 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(mut_mut)] +fn fun(x : &mut &mut u32) -> bool { //~ERROR + **x > 0 +} + +#[deny(mut_mut)] +fn main() { + let mut x = &mut &mut 1u32; //~ERROR + if fun(x) { + let y : &mut &mut &mut u32 = &mut &mut &mut 2; + //~^ ERROR + //~^^ ERROR + //~^^^ ERROR + //~^^^^ ERROR + ***y + **x; + } +}