From 764eedd0508a53b5184741bd05b8d20ea1034c42 Mon Sep 17 00:00:00 2001 From: wartman4404 Date: Tue, 3 Nov 2015 21:11:40 -0600 Subject: [PATCH] check for Deref conversions --- README.md | 2 +- src/eta_reduction.rs | 6 +----- src/map_clone.rs | 17 ++++++++--------- src/utils.rs | 4 ++++ tests/compile-fail/map_clone.rs | 23 +++++++++++++++++++++++ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index fcfeca1509eb..4c23d6994d29 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 71 lints included in this crate: +There are 72 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 7226a4bad05a..855ea51ee8ea 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; -use utils::{snippet, span_lint}; +use utils::{snippet, span_lint, is_adjusted}; #[allow(missing_copy_implementations)] @@ -32,10 +32,6 @@ impl LateLintPass for EtaPass { } } -fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { - cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() -} - fn check_closure(cx: &LateContext, expr: &Expr) { if let ExprClosure(_, ref decl, ref blk) = expr.node { if !blk.stmts.is_empty() { diff --git a/src/map_clone.rs b/src/map_clone.rs index 570ee91dd7bd..e93a82211458 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::Ident; use utils::OPTION_PATH; -use utils::{match_trait_method, match_type, snippet, span_help_and_lint}; +use utils::{is_adjusted, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; declare_lint!(pub MAP_CLONE, Warn, @@ -30,7 +30,7 @@ impl LateLintPass for MapClonePass { let Some(type_name) = get_type_name(cx, expr, &args[0]) ], { // look for derefs, for .map(|x| *x) - if only_derefs(&*closure_expr, arg_ident) && + if only_derefs(cx, &*closure_expr, arg_ident) && // .cloned() only removes one level of indirection, don't lint on more walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 { @@ -85,13 +85,12 @@ fn get_arg_name(pat: &Pat) -> Option { } } -fn only_derefs(expr: &Expr, id: Ident) -> bool { - if expr_eq_ident(expr, id) { - true - } else if let ExprUnary(UnDeref, ref subexpr) = expr.node { - only_derefs(subexpr, id) - } else { - false +fn only_derefs(cx: &LateContext, expr: &Expr, id: Ident) -> bool { + match expr.node { + ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => { + only_derefs(cx, subexpr, id) + }, + _ => expr_eq_ident(expr, id), } } diff --git a/src/utils.rs b/src/utils.rs index 7cbb532cf22e..757d7bc379d7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -347,6 +347,10 @@ pub fn is_integer_literal(expr: &Expr, value: u64) -> bool false } +pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { + cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() +} + /// Produce a nested chain of if-lets and ifs from the patterns: /// /// if_let_chain! { diff --git a/tests/compile-fail/map_clone.rs b/tests/compile-fail/map_clone.rs index 9d9f253defe8..f6241114a83c 100644 --- a/tests/compile-fail/map_clone.rs +++ b/tests/compile-fail/map_clone.rs @@ -5,6 +5,8 @@ #![allow(unused)] +use std::ops::Deref; + fn map_clone_iter() { let x = [1,2,3]; x.iter().map(|y| y.clone()); //~ ERROR you seem to be using .map() @@ -66,4 +68,25 @@ fn map_clone_other() { x.map(|y| *y); } +#[derive(Copy, Clone)] +struct UnusualDeref; +static NINE: i32 = 9; + +impl Deref for UnusualDeref { + type Target = i32; + fn deref(&self) -> &i32 { &NINE } +} + +fn map_clone_deref() { + let x = Some(UnusualDeref); + let _: Option = x.as_ref().map(|y| *y); //~ ERROR you seem to be using .map() + //~^ HELP try + + // Not linted: using deref conversion + let _: Option = x.map(|y| *y); + + // Not linted: using regular deref but also deref conversion + let _: Option = x.as_ref().map(|y| **y); +} + fn main() { }