@@ -4,13 +4,12 @@ use clippy_utils::{
4
4
ty:: implements_trait,
5
5
} ;
6
6
use rustc_errors:: Applicability ;
7
- use rustc_hir:: { def:: Res , Expr , ExprKind , ImplItem , ImplItemKind , ItemKind , LangItem , Node , PatKind , UnOp } ;
8
- use rustc_hir :: { ExprKind , ImplItem , ImplItemKind , Node , UnOp } ;
7
+ use rustc_hir:: { def:: Res , Expr , ExprKind , ImplItem , ImplItemKind , ItemKind , LangItem , Node , UnOp } ;
8
+ use rustc_hir_analysis :: hir_ty_to_ty ;
9
9
use rustc_lint:: { LateContext , LateLintPass } ;
10
10
use rustc_middle:: ty:: EarlyBinder ;
11
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
- use rustc_span:: { sym, symbol} ;
13
- use std:: borrow:: Cow ;
12
+ use rustc_span:: { sym, symbol:: kw} ;
14
13
15
14
declare_clippy_lint ! {
16
15
/// ### What it does
@@ -61,31 +60,39 @@ declare_clippy_lint! {
61
60
/// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
62
61
/// introduce an error upon refactoring.
63
62
///
63
+ /// ### Limitations
64
+ /// Will not lint if `Self` and `Rhs` do not have the same type.
65
+ ///
64
66
/// ### Example
65
- /// ```rust,ignore
67
+ /// ```rust
68
+ /// # use std::cmp::Ordering;
66
69
/// #[derive(Eq, PartialEq)]
67
70
/// struct A(u32);
68
71
///
69
72
/// impl Ord for A {
70
73
/// fn cmp(&self, other: &Self) -> Ordering {
71
- /// todo!();
74
+ /// // ...
75
+ /// # todo!();
72
76
/// }
73
77
/// }
74
78
///
75
79
/// impl PartialOrd for A {
76
80
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
77
- /// todo!();
81
+ /// // ...
82
+ /// # todo!();
78
83
/// }
79
84
/// }
80
85
/// ```
81
86
/// Use instead:
82
- /// ```rust,ignore
87
+ /// ```rust
88
+ /// # use std::cmp::Ordering;
83
89
/// #[derive(Eq, PartialEq)]
84
90
/// struct A(u32);
85
91
///
86
92
/// impl Ord for A {
87
93
/// fn cmp(&self, other: &Self) -> Ordering {
88
- /// todo!();
94
+ /// // ...
95
+ /// # todo!();
89
96
/// }
90
97
/// }
91
98
///
@@ -105,17 +112,18 @@ declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRE
105
112
impl LateLintPass < ' _ > for IncorrectImpls {
106
113
#[ expect( clippy:: too_many_lines) ]
107
114
fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , impl_item : & ImplItem < ' _ > ) {
108
- let node = get_parent_node ( cx. tcx , impl_item. hir_id ( ) ) ;
109
- let Some ( Node :: Item ( item) ) = node else {
115
+ let Some ( Node :: Item ( item) ) = get_parent_node ( cx. tcx , impl_item. hir_id ( ) ) else {
110
116
return ;
111
117
} ;
112
118
let Some ( trait_impl) = cx. tcx . impl_trait_ref ( item. owner_id ) . map ( EarlyBinder :: skip_binder) else {
113
119
return ;
114
120
} ;
115
- let trait_impl_def_id = trait_impl. def_id ;
116
121
if cx. tcx . is_automatically_derived ( item. owner_id . to_def_id ( ) ) {
117
122
return ;
118
123
}
124
+ let ItemKind :: Impl ( imp) = item. kind else {
125
+ return ;
126
+ } ;
119
127
let ImplItemKind :: Fn ( _, impl_item_id) = cx. tcx . hir ( ) . impl_item ( impl_item. impl_item_id ( ) ) . kind else {
120
128
return ;
121
129
} ;
@@ -124,7 +132,7 @@ impl LateLintPass<'_> for IncorrectImpls {
124
132
return ;
125
133
} ;
126
134
127
- if cx. tcx . is_diagnostic_item ( sym:: Clone , trait_impl_def_id )
135
+ if cx. tcx . is_diagnostic_item ( sym:: Clone , trait_impl . def_id )
128
136
&& let Some ( copy_def_id) = cx. tcx . get_diagnostic_item ( sym:: Copy )
129
137
&& implements_trait (
130
138
cx,
@@ -136,9 +144,9 @@ impl LateLintPass<'_> for IncorrectImpls {
136
144
if impl_item. ident . name == sym:: clone {
137
145
if block. stmts . is_empty ( )
138
146
&& let Some ( expr) = block. expr
139
- && let ExprKind :: Unary ( UnOp :: Deref , inner ) = expr. kind
140
- && let ExprKind :: Path ( qpath) = inner . kind
141
- && last_path_segment ( & qpath) . ident . name == symbol :: kw:: SelfLower
147
+ && let ExprKind :: Unary ( UnOp :: Deref , deref ) = expr. kind
148
+ && let ExprKind :: Path ( qpath) = deref . kind
149
+ && last_path_segment ( & qpath) . ident . name == kw:: SelfLower
142
150
{ } else {
143
151
span_lint_and_sugg (
144
152
cx,
@@ -160,7 +168,7 @@ impl LateLintPass<'_> for IncorrectImpls {
160
168
INCORRECT_CLONE_IMPL_ON_COPY_TYPE ,
161
169
impl_item. span ,
162
170
"incorrect implementation of `clone_from` on a `Copy` type" ,
163
- "remove this " ,
171
+ "remove it " ,
164
172
String :: new ( ) ,
165
173
Applicability :: MaybeIncorrect ,
166
174
) ;
@@ -169,7 +177,7 @@ impl LateLintPass<'_> for IncorrectImpls {
169
177
}
170
178
}
171
179
172
- if cx. tcx . is_diagnostic_item ( sym:: PartialOrd , trait_impl_def_id )
180
+ if cx. tcx . is_diagnostic_item ( sym:: PartialOrd , trait_impl . def_id )
173
181
&& impl_item. ident . name == sym:: partial_cmp
174
182
&& let Some ( ord_def_id) = cx
175
183
. tcx
@@ -198,12 +206,9 @@ impl LateLintPass<'_> for IncorrectImpls {
198
206
&& cmp_path. ident . name == sym:: cmp
199
207
&& let Res :: Local ( ..) = path_res ( cx, other_expr)
200
208
{ } else {
201
- // If lhs and rhs are not the same type, bail. This makes creating a valid
209
+ // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
202
210
// suggestion tons more complex.
203
- if let Some ( lhs) = trait_impl. substs . get ( 0 )
204
- && let Some ( rhs) = trait_impl. substs . get ( 1 )
205
- && lhs != rhs
206
- {
211
+ if let [ lhs, rhs, ..] = trait_impl. substs . as_slice ( ) && lhs != rhs {
207
212
return ;
208
213
}
209
214
@@ -213,22 +218,23 @@ impl LateLintPass<'_> for IncorrectImpls {
213
218
item. span ,
214
219
"incorrect implementation of `partial_cmp` on an `Ord` type" ,
215
220
|diag| {
216
- let ( help, app) = if let Some ( other) = body. params . get ( 1 )
217
- && let PatKind :: Binding ( _, _, other_ident, ..) = other. pat . kind
218
- {
219
- (
220
- Cow :: Owned ( format ! ( "{{ Some(self.cmp({})) }}" , other_ident. name) ) ,
221
- Applicability :: Unspecified ,
222
- )
221
+ let [ _, other] = body. params else {
222
+ return ;
223
+ } ;
224
+
225
+ let suggs = if let Some ( other_ident) = other. pat . simple_ident ( ) {
226
+ vec ! [ ( block. span, format!( "{{ Some(self.cmp({})) }}" , other_ident. name) ) ]
223
227
} else {
224
- ( Cow :: Borrowed ( "{ Some(self.cmp(...)) }" ) , Applicability :: HasPlaceholders )
228
+ vec ! [
229
+ ( block. span, "{ Some(self.cmp(other)) }" . to_owned( ) ) ,
230
+ ( other. pat. span, "other" . to_owned( ) ) ,
231
+ ]
225
232
} ;
226
233
227
- diag. span_suggestion (
228
- block. span ,
234
+ diag. multipart_suggestion (
229
235
"change this to" ,
230
- help ,
231
- app ,
236
+ suggs ,
237
+ Applicability :: Unspecified ,
232
238
) ;
233
239
}
234
240
) ;
0 commit comments