|
| 1 | +// rustfmt-max_width: 120 |
| 2 | + |
| 3 | +fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { |
| 4 | + let clone_id = match cx.tcx.lang_items().clone_trait() { |
| 5 | + Some(id) if trait_ref.trait_def_id() == Some(id) => id, |
| 6 | + _ => return, |
| 7 | + }; |
| 8 | + let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return }; |
| 9 | + let (ty_adt, ty_subs) = match *ty.kind() { |
| 10 | + // Unions can't derive clone. |
| 11 | + ty::Adt(adt, subs) if !adt.is_union() => (adt, subs), |
| 12 | + _ => return, |
| 13 | + }; |
| 14 | + // If the current self type doesn't implement Copy (due to generic constraints), search to see if |
| 15 | + // there's a Copy impl for any instance of the adt. |
| 16 | + if !is_copy(cx, ty) { |
| 17 | + if ty_subs.non_erasable_generics().next().is_some() { |
| 18 | + let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { |
| 19 | + impls |
| 20 | + .iter() |
| 21 | + .any(|&id| matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())) |
| 22 | + }); |
| 23 | + if !has_copy_impl { |
| 24 | + return; |
| 25 | + } |
| 26 | + } else { |
| 27 | + return; |
| 28 | + } |
| 29 | + } |
| 30 | + // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for |
| 31 | + // this impl. |
| 32 | + if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) { |
| 33 | + return; |
| 34 | + } |
| 35 | + // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`. |
| 36 | + // https://github.com/rust-lang/rust-clippy/issues/10188 |
| 37 | + if ty_adt.repr().packed() |
| 38 | + && ty_subs |
| 39 | + .iter() |
| 40 | + .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(_) | GenericArgKind::Const(_))) |
| 41 | + { |
| 42 | + return; |
| 43 | + } |
| 44 | + |
| 45 | + span_lint_and_note( |
| 46 | + cx, |
| 47 | + EXPL_IMPL_CLONE_ON_COPY, |
| 48 | + item.span, |
| 49 | + "you are implementing `Clone` explicitly on a `Copy` type", |
| 50 | + Some(item.span), |
| 51 | + "consider deriving `Clone` or removing `Copy`", |
| 52 | + ); |
| 53 | +} |
0 commit comments