@@ -2,9 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils:: { get_trait_def_id, match_qpath, path_res, ty:: implements_trait} ;
33use rustc_errors:: Applicability ;
44use rustc_hir:: def:: Res ;
5- use rustc_hir:: { Expr , ExprKind , Impl , ImplItemKind , Item , ItemKind , PatKind , QPath } ;
5+ use rustc_hir:: { Expr , ExprKind , Impl , ImplItemKind , Item , ItemKind , PatKind } ;
66use rustc_hir_analysis:: hir_ty_to_ty;
77use rustc_lint:: { LateContext , LateLintPass } ;
8+ use rustc_middle:: ty:: { EarlyBinder , TraitRef } ;
89use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
910use rustc_span:: def_id:: DefId ;
1011use rustc_span:: sym;
@@ -65,33 +66,46 @@ pub struct ManualPartialOrdAndOrdImpl {
6566 pub ord_def_id : OnceCell < DefId > ,
6667}
6768
69+ // TODO: The number of if_chain! calls makes this is a bit hard to follow, can that be reduced?
70+ // or more generally, can this be done cleaner?
71+
6872impl LateLintPass < ' _ > for ManualPartialOrdAndOrdImpl {
6973 fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
7074 if_chain ! {
7175 if let ItemKind :: Impl ( imp) = & item. kind;
72- if let Some ( impl_trait_ref) = cx. tcx. impl_trait_ref( item. owner_id) ;
73- let partial_ord_def_id = impl_trait_ref. skip_binder ( ) . def_id;
76+ if let Some ( impl_trait_ref) = cx. tcx. impl_trait_ref( item. owner_id) . map ( EarlyBinder :: skip_binder ) ;
77+ let partial_ord_def_id = impl_trait_ref. def_id;
7478 if cx. tcx. is_diagnostic_item( sym:: PartialOrd , partial_ord_def_id) ;
7579 if !cx. tcx. is_automatically_derived( item. owner_id. to_def_id( ) ) ;
7680 then {
77- lint_impl_body( self , cx, imp, item) ;
81+ lint_impl_body( self , cx, imp, item, impl_trait_ref ) ;
7882 }
7983 }
8084 }
8185}
8286
8387#[ allow( clippy:: unnecessary_def_path) ] // ???
84- // ^ line 91, that can't be changed without causing compilation to fail
85- fn lint_impl_body ( conf : & mut ManualPartialOrdAndOrdImpl , cx : & LateContext < ' _ > , imp : & Impl < ' _ > , item : & Item < ' _ > ) {
88+ fn lint_impl_body < ' tcx > (
89+ conf : & mut ManualPartialOrdAndOrdImpl ,
90+ cx : & LateContext < ' tcx > ,
91+ imp : & Impl < ' _ > ,
92+ item : & Item < ' _ > ,
93+ impl_trait_ref : TraitRef < ' tcx > ,
94+ ) {
8695 for imp_item in imp. items {
8796 if_chain ! {
8897 if imp_item. ident. name == sym:: partial_cmp;
8998 if let ImplItemKind :: Fn ( _, id) = cx. tcx. hir( ) . impl_item( imp_item. id) . kind;
9099 then {
91100 let body = cx. tcx. hir( ) . body( id) ;
101+ // TODO: This can't be changed without causing compilation to fail
92102 let ord_def_id = conf. ord_def_id. get_or_init( || get_trait_def_id( cx, & [ "core" , "cmp" , "Ord" ] ) . unwrap( ) ) ;
93- if let ExprKind :: Block ( block, ..)
94- = body. value. kind && implements_trait( cx, hir_ty_to_ty( cx. tcx, imp. self_ty) , * ord_def_id, & [ ] )
103+ if let ExprKind :: Block ( block, ..) = body. value. kind && implements_trait(
104+ cx,
105+ hir_ty_to_ty( cx. tcx, imp. self_ty) ,
106+ * ord_def_id,
107+ impl_trait_ref. substs,
108+ )
95109 {
96110 if_chain! {
97111 if block. stmts. is_empty( ) ;
@@ -101,22 +115,26 @@ fn lint_impl_body(conf: &mut ManualPartialOrdAndOrdImpl, cx: &LateContext<'_>, i
101115 if let ExprKind :: MethodCall ( cmp_path, _, [ other_expr] , ..) = cmp_expr. kind;
102116 if cmp_path. ident. name == sym:: cmp;
103117 if let Res :: Local ( ..) = path_res( cx, other_expr) ;
118+ // TODO: Self explanatory
104119 then { }
105120 else {
106121 span_lint_and_then(
107122 cx,
108123 MANUAL_PARTIAL_ORD_AND_ORD_IMPL ,
109124 item. span,
110125 "manual implementation of `PartialOrd` when `Ord` is already implemented" ,
126+ // TODO: Is this how this should be done? Should we instead suggest
127+ // changing the entire block, including the name
128+ // of (by default) other if we can't find it?
111129 |diag| {
112130 if let Some ( param) = body. params. get( 1 )
113131 && let PatKind :: Binding ( _, _, param_ident, ..) = param. pat. kind
114132 {
115133 diag. span_suggestion(
116134 block. span,
117135 "change this to" ,
118- format!( "{{ Some(self.cmp({})) }}" ,
119- param_ident . name ) ,
136+ format!( "{{ Some(self.cmp({})) }}" , param_ident . name ) ,
137+ // TODO: This is always correct afaik.
120138 Applicability :: MaybeIncorrect
121139 ) ;
122140 } else {
0 commit comments