match .map(Clone::clone)

This commit is contained in:
llogiq
2015-11-05 17:11:41 +01:00
parent 729b2daf27
commit a0cd8fc943
3 changed files with 56 additions and 38 deletions

View File

@@ -1,8 +1,8 @@
use rustc::lint::*; use rustc::lint::*;
use rustc_front::hir::*; use rustc_front::hir::*;
use syntax::ast::Ident; use syntax::ast::Ident;
use utils::OPTION_PATH; use utils::{CLONE_PATH, OPTION_PATH};
use utils::{is_adjusted, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint};
use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth};
declare_lint!(pub MAP_CLONE, Warn, declare_lint!(pub MAP_CLONE, Warn,
@@ -14,12 +14,13 @@ pub struct MapClonePass;
impl LateLintPass for MapClonePass { impl LateLintPass for MapClonePass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
// call to .map()
if let ExprMethodCall(name, _, ref args) = expr.node {
if name.node.as_str() == "map" && args.len() == 2 {
match args[1].node {
ExprClosure(_, ref decl, ref blk) => {
if_let_chain! { if_let_chain! {
[ [
// call to .map()
let ExprMethodCall(name, _, ref args) = expr.node,
name.node.as_str() == "map" && args.len() == 2,
let ExprClosure(_, ref decl, ref blk) = args[1].node,
// just one expression in the closure // just one expression in the closure
blk.stmts.is_empty(), blk.stmts.is_empty(),
let Some(ref closure_expr) = blk.expr, let Some(ref closure_expr) = blk.expr,
@@ -54,6 +55,20 @@ impl LateLintPass for MapClonePass {
} }
} }
} }
},
ExprPath(_, ref path) => {
if match_path(path, &CLONE_PATH) {
let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_");
span_help_and_lint(cx, MAP_CLONE, expr.span, &format!(
"you seem to be using .map() to clone the contents of an {}, consider \
using `.cloned()`", type_name),
&format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")));
}
}
_ => (),
}
}
}
} }
} }

View File

@@ -17,6 +17,7 @@ pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"];
pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"];
pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"];
/// Produce a nested chain of if-lets and ifs from the patterns: /// Produce a nested chain of if-lets and ifs from the patterns:
/// ///

View File

@@ -15,6 +15,8 @@ fn map_clone_iter() {
//~^ HELP try //~^ HELP try
x.iter().map(|y| *y); //~ ERROR you seem to be using .map() x.iter().map(|y| *y); //~ ERROR you seem to be using .map()
//~^ HELP try //~^ HELP try
x.iter().map(Clone::clone); //~ ERROR you seem to be using .map()
//~^ HELP try
} }
fn map_clone_option() { fn map_clone_option() {