@@ -4,12 +4,12 @@ use clippy_utils::{
44 ty:: implements_trait,
55} ;
66use rustc_errors:: Applicability ;
7- use rustc_hir:: { def:: Res , Expr , ExprKind , ImplItem , ImplItemKind , ItemKind , LangItem , Node , PatKind , UnOp } ;
7+ use rustc_hir:: { def:: Res , Expr , ExprKind , ImplItem , ImplItemKind , ItemKind , LangItem , Node , UnOp } ;
88use rustc_hir_analysis:: hir_ty_to_ty;
99use rustc_lint:: { LateContext , LateLintPass } ;
1010use rustc_middle:: ty:: EarlyBinder ;
1111use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12- use rustc_span:: { sym, symbol} ;
12+ use rustc_span:: { sym, symbol:: kw } ;
1313use std:: borrow:: Cow ;
1414
1515declare_clippy_lint ! {
@@ -61,31 +61,39 @@ declare_clippy_lint! {
6161 /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
6262 /// introduce an error upon refactoring.
6363 ///
64+ /// ### Limitations
65+ /// Will not lint if `Self` and `Rhs` do not have the same type.
66+ ///
6467 /// ### Example
65- /// ```rust,ignore
68+ /// ```rust
69+ /// # use std::cmp::Ordering;
6670 /// #[derive(Eq, PartialEq)]
6771 /// struct A(u32);
6872 ///
6973 /// impl Ord for A {
7074 /// fn cmp(&self, other: &Self) -> Ordering {
71- /// todo!();
75+ /// // ...
76+ /// # todo!();
7277 /// }
7378 /// }
7479 ///
7580 /// impl PartialOrd for A {
7681 /// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
77- /// todo!();
82+ /// // ...
83+ /// # todo!();
7884 /// }
7985 /// }
8086 /// ```
8187 /// Use instead:
82- /// ```rust,ignore
88+ /// ```rust
89+ /// # use std::cmp::Ordering;
8390 /// #[derive(Eq, PartialEq)]
8491 /// struct A(u32);
8592 ///
8693 /// impl Ord for A {
8794 /// fn cmp(&self, other: &Self) -> Ordering {
88- /// todo!();
95+ /// // ...
96+ /// # todo!();
8997 /// }
9098 /// }
9199 ///
@@ -105,8 +113,7 @@ declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRE
105113impl LateLintPass < ' _ > for IncorrectImpls {
106114 #[ expect( clippy:: too_many_lines) ]
107115 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 {
116+ let Some ( Node :: Item ( item) ) = get_parent_node ( cx. tcx , impl_item. hir_id ( ) ) else {
110117 return ;
111118 } ;
112119 let ItemKind :: Impl ( imp) = item. kind else {
@@ -115,7 +122,6 @@ impl LateLintPass<'_> for IncorrectImpls {
115122 let Some ( trait_impl) = cx. tcx . impl_trait_ref ( item. owner_id ) . map ( EarlyBinder :: skip_binder) else {
116123 return ;
117124 } ;
118- let trait_impl_def_id = trait_impl. def_id ;
119125 if cx. tcx . is_automatically_derived ( item. owner_id . to_def_id ( ) ) {
120126 return ;
121127 }
@@ -127,7 +133,7 @@ impl LateLintPass<'_> for IncorrectImpls {
127133 return ;
128134 } ;
129135
130- if cx. tcx . is_diagnostic_item ( sym:: Clone , trait_impl_def_id )
136+ if cx. tcx . is_diagnostic_item ( sym:: Clone , trait_impl . def_id )
131137 && let Some ( copy_def_id) = cx. tcx . get_diagnostic_item ( sym:: Copy )
132138 && implements_trait (
133139 cx,
@@ -139,9 +145,9 @@ impl LateLintPass<'_> for IncorrectImpls {
139145 if impl_item. ident . name == sym:: clone {
140146 if block. stmts . is_empty ( )
141147 && let Some ( expr) = block. expr
142- && let ExprKind :: Unary ( UnOp :: Deref , inner ) = expr. kind
143- && let ExprKind :: Path ( qpath) = inner . kind
144- && last_path_segment ( & qpath) . ident . name == symbol :: kw:: SelfLower
148+ && let ExprKind :: Unary ( UnOp :: Deref , deref ) = expr. kind
149+ && let ExprKind :: Path ( qpath) = deref . kind
150+ && last_path_segment ( & qpath) . ident . name == kw:: SelfLower
145151 { } else {
146152 span_lint_and_sugg (
147153 cx,
@@ -163,7 +169,7 @@ impl LateLintPass<'_> for IncorrectImpls {
163169 INCORRECT_CLONE_IMPL_ON_COPY_TYPE ,
164170 impl_item. span ,
165171 "incorrect implementation of `clone_from` on a `Copy` type" ,
166- "remove this " ,
172+ "remove it " ,
167173 String :: new ( ) ,
168174 Applicability :: MaybeIncorrect ,
169175 ) ;
@@ -172,7 +178,7 @@ impl LateLintPass<'_> for IncorrectImpls {
172178 }
173179 }
174180
175- if cx. tcx . is_diagnostic_item ( sym:: PartialOrd , trait_impl_def_id )
181+ if cx. tcx . is_diagnostic_item ( sym:: PartialOrd , trait_impl . def_id )
176182 && impl_item. ident . name == sym:: partial_cmp
177183 && let Some ( ord_def_id) = cx
178184 . tcx
@@ -203,10 +209,7 @@ impl LateLintPass<'_> for IncorrectImpls {
203209 { } else {
204210 // If lhs and rhs are not the same type, bail. This makes creating a valid
205211 // suggestion tons more complex.
206- if let Some ( lhs) = trait_impl. substs . get ( 0 )
207- && let Some ( rhs) = trait_impl. substs . get ( 1 )
208- && lhs != rhs
209- {
212+ if let [ lhs, rhs, ..] = trait_impl. substs . as_slice ( ) && lhs != rhs {
210213 return ;
211214 }
212215
@@ -216,22 +219,23 @@ impl LateLintPass<'_> for IncorrectImpls {
216219 item. span ,
217220 "incorrect implementation of `partial_cmp` on an `Ord` type" ,
218221 |diag| {
219- let ( help, app) = if let Some ( other) = body. params . get ( 1 )
220- && let PatKind :: Binding ( _, _, other_ident, ..) = other. pat . kind
221- {
222- (
223- Cow :: Owned ( format ! ( "{{ Some(self.cmp({})) }}" , other_ident. name) ) ,
224- Applicability :: Unspecified ,
225- )
222+ let [ _, other] = body. params else {
223+ return ;
224+ } ;
225+
226+ let suggs = if let Some ( other_ident) = other. pat . simple_ident ( ) {
227+ vec ! [ ( block. span, format!( "{{ Some(self.cmp({})) }}" , other_ident. name) ) ]
226228 } else {
227- ( Cow :: Borrowed ( "{ Some(self.cmp(...)) }" ) , Applicability :: HasPlaceholders )
229+ vec ! [
230+ ( block. span, "{ Some(self.cmp(other)) }" . to_owned( ) ) ,
231+ ( other. pat. span, "other" . to_owned( ) ) ,
232+ ]
228233 } ;
229234
230- diag. span_suggestion (
231- block. span ,
235+ diag. multipart_suggestion (
232236 "change this to" ,
233- help ,
234- app ,
237+ suggs ,
238+ Applicability :: Unspecified ,
235239 ) ;
236240 }
237241 ) ;
0 commit comments