From: wartman4404 Date: Wed, 4 Nov 2015 03:11:40 +0000 (-0600) Subject: check for Deref conversions X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=764eedd0508a53b5184741bd05b8d20ea1034c42;p=rust.git check for Deref conversions --- diff --git a/README.md b/README.md index fcfeca1509e..4c23d6994d2 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 7226a4bad05..855ea51ee8e 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -2,7 +2,7 @@ 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 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { } } -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 570ee91dd7b..e93a8221145 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -2,7 +2,7 @@ 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 @@ fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { 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 7cbb532cf22..757d7bc379d 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 9d9f253defe..f6241114a83 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() { }