Repository: rust-lang/rust-clippy (Rust)

Issue:
iter_cloned_collect false positive with custom From/IntoIterator impl
### Summary

When `FromIterator` is implemented for a type inside an another iterator, `.collect()`  is able to do run the inner iterator as well. Clippy doesn't recognize this case, and instead assumes that `.iter().cloned().collect()` to a `Vec<_>` always has the same resulting type than `to_vec()`.  This also occurs with `.iter().copied().collect()`.

### Lint Name

iter_cloned_collect and iter_cloned_collect

### Reproducer

I tried this code:

```rust
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 main() {
    let examples = vec![Example(1), Example(0x1234)];
    let encoded: Vec<u8> = examples.iter().cloned().collect();
    assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]);
}

```

I saw this happen:

```
warning: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
  --> src/main.rs:17:36
   |
17 |     let encoded: Vec<u8> = examples.iter().copied().collect();
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
   |
   = note: `#[warn(clippy::iter_cloned_collect)]` on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
```

I expected to see this happen:

No warning, as the `to_vec` cannot do the required conversion.

### Version

```text
rustc 1.62.0 (a8314ef7d 2022-06-27)
binary: rustc
commit-hash: a8314ef7d0ec7b75c336af2c9857bfaf43002bfc
commit-date: 2022-06-27
host: x86_64-unknown-linux-gnu
release: 1.62.0
LLVM version: 14.0.5
```


### Additional Labels

@rustbot label +l-suggestion-causes-error


Discussion:
**Error**: Label l-suggestion-causes-error can only be set by Rust team members

Please file an issue on GitHub at [triagebot](https://github.com/rust-lang/triagebot) if there's a problem with this bot, or reach out on [#t-infra](https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra) on Zulip.




Patch:
diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs
index 49de83885a1c..17cc07b91c5d 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(


Test patch:
diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed
index e9fb44e89598..231fac7cdde7 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 c9b8abcc9a0d..e73b6ecae802 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 119698cb4634..f8a507943270 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