@@ -371,8 +371,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
371371 if op. is_comparison ( ) {
372372 check_nan ( cx, left, expr) ;
373373 check_nan ( cx, right, expr) ;
374- check_to_owned ( cx, left, right) ;
375- check_to_owned ( cx, right, left) ;
374+ check_to_owned ( cx, left, right, true ) ;
375+ check_to_owned ( cx, right, left, false ) ;
376376 }
377377 if ( op == BinOpKind :: Eq || op == BinOpKind :: Ne ) && ( is_float ( cx, left) || is_float ( cx, right) ) {
378378 if is_allowed ( cx, left) || is_allowed ( cx, right) {
@@ -570,28 +570,38 @@ fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
570570 matches ! ( & walk_ptrs_ty( cx. tables. expr_ty( expr) ) . kind, ty:: Array ( _, _) )
571571}
572572
573- fn check_to_owned ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , other : & Expr < ' _ > ) {
574- fn symmetric_partial_eq < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , lhs : Ty < ' tcx > , rhs : Ty < ' tcx > ) -> bool {
575- if let Some ( trait_def_id) = cx. tcx . lang_items ( ) . eq_trait ( ) {
576- return implements_trait ( cx, lhs, trait_def_id, & [ rhs. into ( ) ] )
577- && implements_trait ( cx, rhs, trait_def_id, & [ lhs. into ( ) ] ) ;
573+ fn check_to_owned ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , other : & Expr < ' _ > , left : bool ) {
574+ #[ derive( Default ) ]
575+ struct EqImpl {
576+ ty_eq_other : bool ,
577+ other_eq_ty : bool ,
578+ }
579+
580+ impl EqImpl {
581+ fn is_implemented ( & self ) -> bool {
582+ self . ty_eq_other || self . other_eq_ty
578583 }
584+ }
579585
580- false
586+ fn symmetric_partial_eq < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , ty : Ty < ' tcx > , other : Ty < ' tcx > ) -> Option < EqImpl > {
587+ cx. tcx . lang_items ( ) . eq_trait ( ) . map ( |def_id| EqImpl {
588+ ty_eq_other : implements_trait ( cx, ty, def_id, & [ other. into ( ) ] ) ,
589+ other_eq_ty : implements_trait ( cx, other, def_id, & [ ty. into ( ) ] ) ,
590+ } )
581591 }
582592
583593 let ( arg_ty, snip) = match expr. kind {
584594 ExprKind :: MethodCall ( .., ref args, _) if args. len ( ) == 1 => {
585595 if match_trait_method ( cx, expr, & paths:: TO_STRING ) || match_trait_method ( cx, expr, & paths:: TO_OWNED ) {
586- ( cx. tables . expr_ty_adjusted ( & args[ 0 ] ) , snippet ( cx, args[ 0 ] . span , ".." ) )
596+ ( cx. tables . expr_ty ( & args[ 0 ] ) , snippet ( cx, args[ 0 ] . span , ".." ) )
587597 } else {
588598 return ;
589599 }
590600 } ,
591601 ExprKind :: Call ( ref path, ref v) if v. len ( ) == 1 => {
592602 if let ExprKind :: Path ( ref path) = path. kind {
593603 if match_qpath ( path, & [ "String" , "from_str" ] ) || match_qpath ( path, & [ "String" , "from" ] ) {
594- ( cx. tables . expr_ty_adjusted ( & v[ 0 ] ) , snippet ( cx, v[ 0 ] . span , ".." ) )
604+ ( cx. tables . expr_ty ( & v[ 0 ] ) , snippet ( cx, v[ 0 ] . span , ".." ) )
595605 } else {
596606 return ;
597607 }
@@ -602,24 +612,19 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
602612 _ => return ,
603613 } ;
604614
605- let other_ty = cx. tables . expr_ty_adjusted ( other) ;
615+ let other_ty = cx. tables . expr_ty ( other) ;
606616
607- let deref_arg_impl_partial_eq_other = arg_ty
608- . builtin_deref ( true )
609- . map_or ( false , |tam| symmetric_partial_eq ( cx, tam. ty , other_ty) ) ;
610- let arg_impl_partial_eq_deref_other = other_ty
617+ let without_deref = symmetric_partial_eq ( cx, arg_ty, other_ty) . unwrap_or_default ( ) ;
618+ let with_deref = arg_ty
611619 . builtin_deref ( true )
612- . map_or ( false , |tam| symmetric_partial_eq ( cx, arg_ty , tam. ty ) ) ;
613- let arg_impl_partial_eq_other = symmetric_partial_eq ( cx , arg_ty , other_ty ) ;
620+ . and_then ( |tam| symmetric_partial_eq ( cx, tam. ty , other_ty ) )
621+ . unwrap_or_default ( ) ;
614622
615- if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
623+ if !with_deref . is_implemented ( ) && !without_deref . is_implemented ( ) {
616624 return ;
617625 }
618626
619- let other_gets_derefed = match other. kind {
620- ExprKind :: Unary ( UnOp :: UnDeref , _) => true ,
621- _ => false ,
622- } ;
627+ let other_gets_derefed = matches ! ( other. kind, ExprKind :: Unary ( UnOp :: UnDeref , _) ) ;
623628
624629 let lint_span = if other_gets_derefed {
625630 expr. span . to ( other. span )
@@ -639,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
639644 return ;
640645 }
641646
642- let try_hint = if deref_arg_impl_partial_eq_other {
643- // suggest deref on the left
644- format ! ( "*{}" , snip)
647+ let expr_snip;
648+ let eq_impl;
649+ if with_deref. is_implemented ( ) {
650+ expr_snip = format ! ( "*{}" , snip) ;
651+ eq_impl = with_deref;
645652 } else {
646- // suggest dropping the to_owned on the left
647- snip . to_string ( )
653+ expr_snip = snip . to_string ( ) ;
654+ eq_impl = without_deref ;
648655 } ;
649656
657+ let span;
658+ let hint;
659+ if ( eq_impl. ty_eq_other && left) || ( eq_impl. other_eq_ty && !left) {
660+ span = expr. span ;
661+ hint = expr_snip;
662+ } else {
663+ span = expr. span . to ( other. span ) ;
664+ if eq_impl. ty_eq_other {
665+ hint = format ! ( "{} == {}" , expr_snip, snippet( cx, other. span, ".." ) ) ;
666+ } else {
667+ hint = format ! ( "{} == {}" , snippet( cx, other. span, ".." ) , expr_snip) ;
668+ }
669+ }
670+
650671 diag. span_suggestion (
651- lint_span ,
672+ span ,
652673 "try" ,
653- try_hint ,
674+ hint ,
654675 Applicability :: MachineApplicable , // snippet
655676 ) ;
656677 } ,
0 commit comments