From b8cdefb6cfab11087943bb41824bb955c655daf1 Mon Sep 17 00:00:00 2001 From: Pyriphlegethon Date: Tue, 29 Sep 2015 13:11:19 +0200 Subject: [PATCH] Add unnecessary mut passed lint --- README.md | 3 ++- src/lib.rs | 3 +++ src/mut_reference.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/mut_reference.rs diff --git a/README.md b/README.md index e15ed7e8fce0..427f4181dea0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 58 lints included in this crate: +There are 59 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -63,6 +63,7 @@ name [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function only demands an immutable reference [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention diff --git a/src/lib.rs b/src/lib.rs index 3c2d870aee2e..2f71d8cc9df7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ pub mod eta_reduction; pub mod identity_op; pub mod minmax; pub mod mut_mut; +pub mod mut_reference; pub mod len_zero; pub mod attrs; pub mod collapsible_if; @@ -66,6 +67,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box eta_reduction::EtaPass); reg.register_late_lint_pass(box identity_op::IdentityOp); reg.register_late_lint_pass(box mut_mut::MutMut); + reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); reg.register_late_lint_pass(box len_zero::LenZero); reg.register_late_lint_pass(box misc::CmpOwned); reg.register_late_lint_pass(box attrs::AttrPass); @@ -138,6 +140,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, + mut_reference::UNNECESSARY_MUT_PASSED, needless_bool::NEEDLESS_BOOL, precedence::PRECEDENCE, ranges::RANGE_STEP_BY_ZERO, diff --git a/src/mut_reference.rs b/src/mut_reference.rs new file mode 100644 index 000000000000..13cf1e1301e4 --- /dev/null +++ b/src/mut_reference.rs @@ -0,0 +1,53 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::span_lint; +use rustc::middle::ty::{TypeAndMut, TypeVariants}; + +declare_lint! { + pub UNNECESSARY_MUT_PASSED, + Warn, + "an argument is passed as a mutable reference although the function only demands an \ + immutable reference" +} + + +#[derive(Copy,Clone)] +pub struct UnnecessaryMutPassed; + +impl LintPass for UnnecessaryMutPassed { + fn get_lints(&self) -> LintArray { + lint_array!(UNNECESSARY_MUT_PASSED) + } +} + +impl LateLintPass for UnnecessaryMutPassed { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let &ExprCall(ref fn_expr, ref arguments) = &e.node { + let borrowed_table = cx.tcx.tables.borrow(); + let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { + Some(funtion_type) => funtion_type, + None => unreachable!(), // A function with unknown type is called. + // If this happened the compiler would have aborted the + // compilation long ago. + }; + if let TypeVariants::TyBareFn(_, ref b) = funtion_type.sty { + let parameters = b.sig.skip_binder().inputs.clone(); + for (argument, parameter) in arguments.iter().zip(parameters.iter()) { + match parameter.sty { + TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | + TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { + if let ExprPath(_, path) = fn_expr.node.clone() { + span_lint(cx, UNNECESSARY_MUT_PASSED, + argument.span, &format!("This argument of the \ + function \"{}\" doesn't need to be mutable", path)); + } + } + }, + _ => {} + } + } + } + } + } +}