]> git.lizzy.rs Git - rust.git/commitdiff
Improve `iter_cloned_collect` suggestions
authorMichael Wright <mikerite@lavabit.com>
Mon, 18 Feb 2019 05:30:50 +0000 (07:30 +0200)
committerMichael Wright <mikerite@lavabit.com>
Mon, 18 Feb 2019 05:30:50 +0000 (07:30 +0200)
Fixes #3704

clippy_lints/src/methods/mod.rs
tests/ui/unnecessary_clone.rs
tests/ui/unnecessary_clone.stderr

index c9b27ef161526c2500fa6969cd97ea18aa61fc56..b1bd43410150419137455ff7c590f22d6829a88e 100644 (file)
@@ -1477,17 +1477,22 @@ fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, new: &hir::Ex
     }
 }
 
-fn lint_iter_cloned_collect(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr]) {
-    if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC)
-        && derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
-    {
-        span_lint(
-            cx,
-            ITER_CLONED_COLLECT,
-            expr.span,
-            "called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
-             more readable",
-        );
+fn lint_iter_cloned_collect<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr]) {
+    if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) {
+        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])) {
+            if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) {
+                span_lint_and_sugg(
+                    cx,
+                    ITER_CLONED_COLLECT,
+                    to_replace,
+                    "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
+                     more readable",
+                    "try",
+                    ".to_vec()".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
     }
 }
 
@@ -1573,7 +1578,7 @@ fn check_fold_with_op(
     };
 }
 
-fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) {
+fn lint_iter_nth<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr], is_mut: bool) {
     let mut_str = if is_mut { "_mut" } else { "" };
     let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
         "slice"
@@ -1596,7 +1601,7 @@ fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::E
     );
 }
 
-fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) {
+fn lint_get_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, get_args: &'tcx [hir::Expr], is_mut: bool) {
     // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap,
     // because they do not implement `IndexMut`
     let mut applicability = Applicability::MachineApplicable;
@@ -1681,7 +1686,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
     }
 }
 
-fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Option<sugg::Sugg<'static>> {
+fn derefs_to_slice<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, ty: Ty<'tcx>) -> Option<&'tcx hir::Expr> {
     fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
         match ty.sty {
             ty::Slice(_) => true,
@@ -1695,17 +1700,17 @@ fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
 
     if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node {
         if path.ident.name == "iter" && may_slice(cx, cx.tables.expr_ty(&args[0])) {
-            sugg::Sugg::hir_opt(cx, &args[0]).map(sugg::Sugg::addr)
+            Some(&args[0])
         } else {
             None
         }
     } else {
         match ty.sty {
-            ty::Slice(_) => sugg::Sugg::hir_opt(cx, expr),
-            ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
+            ty::Slice(_) => Some(expr),
+            ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
             ty::Ref(_, inner, _) => {
                 if may_slice(cx, inner) {
-                    sugg::Sugg::hir_opt(cx, expr)
+                    Some(expr)
                 } else {
                     None
                 }
index fee6b30a97b6c696b7354a569bafa71175ffb57e..e7fceab01c6d877c5d23778287d7f641ba10ab30 100644 (file)
@@ -66,6 +66,18 @@ fn iter_clone_collect() {
     let v2: Vec<isize> = v.iter().cloned().collect();
     let v3: HashSet<isize> = v.iter().cloned().collect();
     let v4: VecDeque<isize> = v.iter().cloned().collect();
+
+    // Handle macro expansion in suggestion
+    let _ : Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
+
+    // Issue #3704
+    unsafe {
+        let _: Vec<u8> = std::ffi::CStr::from_ptr(std::ptr::null())
+            .to_bytes()
+            .iter()
+            .cloned()
+            .collect();
+    }
 }
 
 mod many_derefs {
index 5cd9b2d337f09454931b9f3f8a59bcdd0345ec8c..13c5a43c8e97572792015122b79c2d785e180447 100644 (file)
@@ -78,19 +78,35 @@ help: or try being explicit about what type to clone
 LL |     let z: &Vec<_> = &std::vec::Vec<i32>::clone(y);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
-  --> $DIR/unnecessary_clone.rs:66:26
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> $DIR/unnecessary_clone.rs:66:27
    |
 LL |     let v2: Vec<isize> = v.iter().cloned().collect();
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
    |
    = note: `-D clippy::iter-cloned-collect` implied by `-D warnings`
 
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> $DIR/unnecessary_clone.rs:71:39
+   |
+LL |     let _ : Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> $DIR/unnecessary_clone.rs:76:24
+   |
+LL |               .to_bytes()
+   |  ________________________^
+LL | |             .iter()
+LL | |             .cloned()
+LL | |             .collect();
+   | |______________________^ help: try: `.to_vec()`
+
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:102:20
+  --> $DIR/unnecessary_clone.rs:114:20
    |
 LL |         let _: E = a.clone();
    |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors