From ab8c6beb8526f9dbf3934835681e1ff9e951ea5b Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Thu, 1 Dec 2022 23:05:53 -0500
Subject: [PATCH] Don't lint `implicit_clone` when the type doesn't implement
 clone

---
 clippy_lints/src/methods/implicit_clone.rs |  4 +++-
 tests/ui/implicit_clone.fixed              | 10 ++++++++++
 tests/ui/implicit_clone.rs                 | 10 ++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs
index 429cdc1918d..06ecbce4e70 100644
--- a/clippy_lints/src/methods/implicit_clone.rs
+++ b/clippy_lints/src/methods/implicit_clone.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::peel_mid_ty_refs;
+use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
 use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -19,6 +19,8 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
         let (input_type, ref_count) = peel_mid_ty_refs(input_type);
         if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
         if return_type == input_type;
+        if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();
+        if implements_trait(cx, return_type, clone_trait, &[]);
         then {
             let mut app = Applicability::MachineApplicable;
             let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed
index 33770fc2a2c..51b1afbe5ac 100644
--- a/tests/ui/implicit_clone.fixed
+++ b/tests/ui/implicit_clone.fixed
@@ -115,4 +115,14 @@ fn main() {
     let pathbuf_ref = &pathbuf_ref;
     let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
     let _ = (**pathbuf_ref).clone();
+
+    struct NoClone;
+    impl ToOwned for NoClone {
+        type Owned = Self;
+        fn to_owned(&self) -> Self {
+            NoClone
+        }
+    }
+    let no_clone = &NoClone;
+    let _ = no_clone.to_owned();
 }
diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs
index fc896525bd2..8a9027433d9 100644
--- a/tests/ui/implicit_clone.rs
+++ b/tests/ui/implicit_clone.rs
@@ -115,4 +115,14 @@ fn main() {
     let pathbuf_ref = &pathbuf_ref;
     let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
     let _ = pathbuf_ref.to_path_buf();
+
+    struct NoClone;
+    impl ToOwned for NoClone {
+        type Owned = Self;
+        fn to_owned(&self) -> Self {
+            NoClone
+        }
+    }
+    let no_clone = &NoClone;
+    let _ = no_clone.to_owned();
 }