@@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind;
33use rustc_errors:: Applicability ;
44use rustc_hir:: intravisit:: FnKind ;
55use rustc_hir:: {
6- def, BinOpKind , BindingAnnotation , Body , Expr , ExprKind , FnDecl , HirId , Mutability , PatKind , Stmt , StmtKind , Ty ,
7- TyKind , UnOp ,
6+ self as hir , def, BinOpKind , BindingAnnotation , Body , Expr , ExprKind , FnDecl , HirId , Mutability , PatKind , Stmt ,
7+ StmtKind , TyKind , UnOp ,
88} ;
99use rustc_lint:: { LateContext , LateLintPass } ;
10- use rustc_middle:: ty;
10+ use rustc_middle:: ty:: { self , Ty } ;
1111use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1212use rustc_span:: hygiene:: DesugaringKind ;
1313use rustc_span:: source_map:: { ExpnKind , Span } ;
@@ -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,19 +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 < ' _ > ) {
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
583+ }
584+ }
585+
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+ } )
591+ }
592+
574593 let ( arg_ty, snip) = match expr. kind {
575594 ExprKind :: MethodCall ( .., ref args, _) if args. len ( ) == 1 => {
576595 if match_trait_method ( cx, expr, & paths:: TO_STRING ) || match_trait_method ( cx, expr, & paths:: TO_OWNED ) {
577- ( cx. tables . expr_ty_adjusted ( & args[ 0 ] ) , snippet ( cx, args[ 0 ] . span , ".." ) )
596+ ( cx. tables . expr_ty ( & args[ 0 ] ) , snippet ( cx, args[ 0 ] . span , ".." ) )
578597 } else {
579598 return ;
580599 }
581600 } ,
582601 ExprKind :: Call ( ref path, ref v) if v. len ( ) == 1 => {
583602 if let ExprKind :: Path ( ref path) = path. kind {
584603 if match_qpath ( path, & [ "String" , "from_str" ] ) || match_qpath ( path, & [ "String" , "from" ] ) {
585- ( cx. tables . expr_ty_adjusted ( & v[ 0 ] ) , snippet ( cx, v[ 0 ] . span , ".." ) )
604+ ( cx. tables . expr_ty ( & v[ 0 ] ) , snippet ( cx, v[ 0 ] . span , ".." ) )
586605 } else {
587606 return ;
588607 }
@@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
593612 _ => return ,
594613 } ;
595614
596- let other_ty = cx. tables . expr_ty_adjusted ( other) ;
597- let partial_eq_trait_id = match cx. tcx . lang_items ( ) . eq_trait ( ) {
598- Some ( id) => id,
599- None => return ,
600- } ;
615+ let other_ty = cx. tables . expr_ty ( other) ;
601616
602- let deref_arg_impl_partial_eq_other = arg_ty. builtin_deref ( true ) . map_or ( false , |tam| {
603- implements_trait ( cx, tam. ty , partial_eq_trait_id, & [ other_ty. into ( ) ] )
604- } ) ;
605- let arg_impl_partial_eq_deref_other = other_ty. builtin_deref ( true ) . map_or ( false , |tam| {
606- implements_trait ( cx, arg_ty, partial_eq_trait_id, & [ tam. ty . into ( ) ] )
607- } ) ;
608- let arg_impl_partial_eq_other = implements_trait ( cx, arg_ty, partial_eq_trait_id, & [ other_ty. into ( ) ] ) ;
617+ let without_deref = symmetric_partial_eq ( cx, arg_ty, other_ty) . unwrap_or_default ( ) ;
618+ let with_deref = arg_ty
619+ . builtin_deref ( true )
620+ . and_then ( |tam| symmetric_partial_eq ( cx, tam. ty , other_ty) )
621+ . unwrap_or_default ( ) ;
609622
610- 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 ( ) {
611624 return ;
612625 }
613626
614- let other_gets_derefed = match other. kind {
615- ExprKind :: Unary ( UnOp :: UnDeref , _) => true ,
616- _ => false ,
617- } ;
627+ let other_gets_derefed = matches ! ( other. kind, ExprKind :: Unary ( UnOp :: UnDeref , _) ) ;
618628
619629 let lint_span = if other_gets_derefed {
620630 expr. span . to ( other. span )
@@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
634644 return ;
635645 }
636646
637- let try_hint = if deref_arg_impl_partial_eq_other {
638- // suggest deref on the left
639- 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;
640652 } else {
641- // suggest dropping the to_owned on the left
642- snip . to_string ( )
653+ expr_snip = snip . to_string ( ) ;
654+ eq_impl = without_deref ;
643655 } ;
644656
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+
645671 diag. span_suggestion (
646- lint_span ,
672+ span ,
647673 "try" ,
648- try_hint ,
674+ hint ,
649675 Applicability :: MachineApplicable , // snippet
650676 ) ;
651677 } ,
@@ -694,7 +720,7 @@ fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool {
694720 }
695721}
696722
697- fn check_cast ( cx : & LateContext < ' _ , ' _ > , span : Span , e : & Expr < ' _ > , ty : & Ty < ' _ > ) {
723+ fn check_cast ( cx : & LateContext < ' _ , ' _ > , span : Span , e : & Expr < ' _ > , ty : & hir :: Ty < ' _ > ) {
698724 if_chain ! {
699725 if let TyKind :: Ptr ( ref mut_ty) = ty. kind;
700726 if let ExprKind :: Lit ( ref lit) = e. kind;
0 commit comments