1
- use clippy_utils:: { diagnostics:: span_lint_and_sugg, get_parent_node, last_path_segment, ty:: implements_trait} ;
1
+ use clippy_utils:: {
2
+ diagnostics:: span_lint_and_sugg,
3
+ get_parent_node, last_path_segment,
4
+ ty:: { implements_trait, is_type_lang_item} ,
5
+ } ;
6
+ use itertools:: Itertools ;
2
7
use rustc_errors:: Applicability ;
3
- use rustc_hir:: { ExprKind , ImplItem , ImplItemKind , ItemKind , Node , UnOp } ;
8
+ use rustc_hir:: { ExprKind , ImplItem , ImplItemKind , ItemKind , LangItem , Node , UnOp } ;
4
9
use rustc_hir_analysis:: hir_ty_to_ty;
5
10
use rustc_lint:: { LateContext , LateLintPass } ;
6
- use rustc_middle:: ty:: EarlyBinder ;
11
+ use rustc_middle:: ty:: { self , EarlyBinder } ;
7
12
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
8
13
use rustc_span:: { sym, symbol} ;
9
14
@@ -15,6 +20,14 @@ declare_clippy_lint! {
15
20
/// If both `Clone` and `Copy` are implemented, they must agree. This is done by dereferencing
16
21
/// `self` in `Clone`'s implementation. Anything else is incorrect.
17
22
///
23
+ /// ### Known issues
24
+ /// While anything other than `*self` is *technically* incorrect, it can often be done as an
25
+ /// optimization, like in the case of `MaybeUninit` for example. Returning a new `MaybeUninit`
26
+ /// is both faster and as correct as `memcpy`ing the original. If this is not the case however,
27
+ /// the lint's advice should almost always be applied.
28
+ ///
29
+ /// Note: This lint ignores `Clone` implementations on types that are just `MaybeUninit`.
30
+ ///
18
31
/// ### Example
19
32
/// ```rust,ignore
20
33
/// #[derive(Eq, PartialEq)]
@@ -43,7 +56,7 @@ declare_clippy_lint! {
43
56
/// ```
44
57
#[ clippy:: version = "1.72.0" ]
45
58
pub INCORRECT_CLONE_IMPL_ON_COPY_TYPE ,
46
- correctness ,
59
+ complexity ,
47
60
"manual implementation of `Clone` on a `Copy` type"
48
61
}
49
62
declare_lint_pass ! ( IncorrectImpls => [ INCORRECT_CLONE_IMPL_ON_COPY_TYPE ] ) ;
@@ -84,7 +97,31 @@ impl LateLintPass<'_> for IncorrectImpls {
84
97
copy_def_id,
85
98
trait_impl. substs ,
86
99
)
100
+ && let ty:: Adt ( def, substs) = hir_ty_to_ty ( cx. tcx , imp. self_ty ) . kind ( )
87
101
{
102
+ let fields = def. all_fields ( ) . collect_vec ( ) ;
103
+ // Necessary as `all` returns true on an empty iterator
104
+ if !fields. is_empty ( )
105
+ && fields. iter ( ) . all ( |field| {
106
+ let ty = field. ty ( cx. tcx , substs) ;
107
+
108
+ match ty. kind ( ) {
109
+ // `MaybeUninit<T>`
110
+ ty:: Adt ( _, _) if is_type_lang_item ( cx, ty, LangItem :: MaybeUninit ) => true ,
111
+ // `[MaybeUninit<T>; N]`
112
+ ty:: Array ( inner_ty, _) | ty:: Slice ( inner_ty)
113
+ if is_type_lang_item ( cx, * inner_ty, LangItem :: MaybeUninit ) =>
114
+ {
115
+ true
116
+ } ,
117
+ // Other cases are likely pretty rare.
118
+ _ => false ,
119
+ }
120
+ } )
121
+ {
122
+ return ;
123
+ }
124
+
88
125
if impl_item. ident . name == sym:: clone {
89
126
if block. stmts . is_empty ( )
90
127
&& let Some ( expr) = block. expr
0 commit comments