about summary refs log tree commit diff
diff options
context:
space:
mode:
authoryanglsh <yanglsh@shanghaitech.edu.cn>2025-03-25 23:00:16 +0800
committeryanglsh <yanglsh@shanghaitech.edu.cn>2025-04-08 20:38:43 +0800
commitee3612401121ccbdbf9c8d8fa6874c6e5128b049 (patch)
treeabcef4648e6ce8278ba733a0122c5fd6c8be601c
parentf74d7ce81371b2573d7a356408251fa4cac3f8d2 (diff)
downloadrust-ee3612401121ccbdbf9c8d8fa6874c6e5128b049.tar.gz
rust-ee3612401121ccbdbf9c8d8fa6874c6e5128b049.zip
fix: `iter_cloned_collect` FP with custom `From`/`IntoIterator` impl
-rw-r--r--clippy_lints/src/methods/iter_cloned_collect.rs10
-rw-r--r--tests/ui/iter_cloned_collect.fixed27
-rw-r--r--tests/ui/iter_cloned_collect.rs27
-rw-r--r--tests/ui/iter_cloned_collect.stderr8
4 files changed, 69 insertions, 3 deletions
diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs
index 49de83885a1..17cc07b91c5 100644
--- a/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -1,16 +1,22 @@
 use crate::methods::utils::derefs_to_slice;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{get_iterator_item_ty, is_type_diagnostic_item};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_span::sym;
 
 use super::ITER_CLONED_COLLECT;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec)
+    let expr_ty = cx.typeck_results().expr_ty(expr);
+    if is_type_diagnostic_item(cx, expr_ty, sym::Vec)
         && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))
+        && let ty::Adt(_, args) = expr_ty.kind()
+        && let Some(iter_item_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty(recv))
+        && let ty::Ref(_, iter_item_ty, _) = iter_item_ty.kind()
+        && *iter_item_ty == args.type_at(0)
         && let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite())
     {
         span_lint_and_sugg(
diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed
index e9fb44e8959..231fac7cdde 100644
--- a/tests/ui/iter_cloned_collect.fixed
+++ b/tests/ui/iter_cloned_collect.fixed
@@ -29,3 +29,30 @@ fn main() {
     let _: Vec<isize> = v.to_vec();
     //~^ iter_cloned_collect
 }
+
+mod issue9119 {
+
+    use std::iter;
+
+    #[derive(Clone)]
+    struct Example(u16);
+
+    impl iter::FromIterator<Example> for Vec<u8> {
+        fn from_iter<T>(iter: T) -> Self
+        where
+            T: IntoIterator<Item = Example>,
+        {
+            iter.into_iter().flat_map(|e| e.0.to_le_bytes()).collect()
+        }
+    }
+
+    fn foo() {
+        let examples = [Example(1), Example(0x1234)];
+        let encoded: Vec<u8> = examples.iter().cloned().collect();
+        assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]);
+
+        let a = [&&String::new()];
+        let v: Vec<&&String> = a.to_vec();
+        //~^ iter_cloned_collect
+    }
+}
diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs
index c9b8abcc9a0..e73b6ecae80 100644
--- a/tests/ui/iter_cloned_collect.rs
+++ b/tests/ui/iter_cloned_collect.rs
@@ -33,3 +33,30 @@ fn main() {
     let _: Vec<isize> = v.iter().copied().collect();
     //~^ iter_cloned_collect
 }
+
+mod issue9119 {
+
+    use std::iter;
+
+    #[derive(Clone)]
+    struct Example(u16);
+
+    impl iter::FromIterator<Example> for Vec<u8> {
+        fn from_iter<T>(iter: T) -> Self
+        where
+            T: IntoIterator<Item = Example>,
+        {
+            iter.into_iter().flat_map(|e| e.0.to_le_bytes()).collect()
+        }
+    }
+
+    fn foo() {
+        let examples = [Example(1), Example(0x1234)];
+        let encoded: Vec<u8> = examples.iter().cloned().collect();
+        assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]);
+
+        let a = [&&String::new()];
+        let v: Vec<&&String> = a.iter().cloned().collect();
+        //~^ iter_cloned_collect
+    }
+}
diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr
index 119698cb463..f8a50794327 100644
--- a/tests/ui/iter_cloned_collect.stderr
+++ b/tests/ui/iter_cloned_collect.stderr
@@ -36,5 +36,11 @@ error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling
 LL |     let _: Vec<isize> = v.iter().copied().collect();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
 
-error: aborting due to 5 previous errors
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+  --> tests/ui/iter_cloned_collect.rs:59:33
+   |
+LL |         let v: Vec<&&String> = a.iter().cloned().collect();
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+
+error: aborting due to 6 previous errors