Handle closure with single expression blocks

This commit is contained in:
mcarton 2016-11-17 19:44:18 +01:00
parent 19c5f5394b
commit 945c027768
No known key found for this signature in database
GPG key ID: 5E427C794CBA45E8
3 changed files with 27 additions and 1 deletions

View file

@ -1,7 +1,7 @@
use rustc::lint::*;
use rustc::hir::*;
use syntax::ast;
use utils::{is_adjusted, match_path, match_trait_method, match_type, paths, snippet,
use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet,
span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth};
/// **What it does:** Checks for mapping `clone()` over an iterator.
@ -31,6 +31,7 @@ impl LateLintPass for Pass {
if name.node.as_str() == "map" && args.len() == 2 {
match args[1].node {
ExprClosure(_, ref decl, ref closure_expr, _) => {
let closure_expr = remove_blocks(closure_expr);
if_let_chain! {[
// nothing special in the argument, besides reference bindings
// (e.g. .map(|&x| x) )

View file

@ -773,3 +773,22 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "automatically_derived")
}
/// Remove blocks around an expression.
///
/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return themselves.
pub fn remove_blocks(expr: &Expr) -> &Expr {
if let ExprBlock(ref block) = expr.node {
if block.stmts.is_empty() {
if let Some(ref expr) = block.expr {
remove_blocks(expr)
} else {
expr
}
} else {
expr
}
} else {
expr
}
}

View file

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