@@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind;
3
3
use rustc_errors:: Applicability ;
4
4
use rustc_hir:: intravisit:: FnKind ;
5
5
use 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 ,
8
8
} ;
9
9
use rustc_lint:: { LateContext , LateLintPass } ;
10
- use rustc_middle:: ty;
10
+ use rustc_middle:: ty:: { self , Ty } ;
11
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
12
use rustc_span:: hygiene:: DesugaringKind ;
13
13
use rustc_span:: source_map:: { ExpnKind , Span } ;
@@ -371,8 +371,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
371
371
if op. is_comparison ( ) {
372
372
check_nan ( cx, left, expr) ;
373
373
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 ) ;
376
376
}
377
377
if ( op == BinOpKind :: Eq || op == BinOpKind :: Ne ) && ( is_float ( cx, left) || is_float ( cx, right) ) {
378
378
if is_allowed ( cx, left) || is_allowed ( cx, right) {
@@ -570,19 +570,38 @@ fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
570
570
matches ! ( & walk_ptrs_ty( cx. tables. expr_ty( expr) ) . kind, ty:: Array ( _, _) )
571
571
}
572
572
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
+
574
593
let ( arg_ty, snip) = match expr. kind {
575
594
ExprKind :: MethodCall ( .., ref args, _) if args. len ( ) == 1 => {
576
595
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 , ".." ) )
578
597
} else {
579
598
return ;
580
599
}
581
600
} ,
582
601
ExprKind :: Call ( ref path, ref v) if v. len ( ) == 1 => {
583
602
if let ExprKind :: Path ( ref path) = path. kind {
584
603
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 , ".." ) )
586
605
} else {
587
606
return ;
588
607
}
@@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
593
612
_ => return ,
594
613
} ;
595
614
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) ;
601
616
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 ( ) ;
609
622
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 ( ) {
611
624
return ;
612
625
}
613
626
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 , _) ) ;
618
628
619
629
let lint_span = if other_gets_derefed {
620
630
expr. span . to ( other. span )
@@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
634
644
return ;
635
645
}
636
646
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;
640
652
} 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 ;
643
655
} ;
644
656
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
+
645
671
diag. span_suggestion (
646
- lint_span ,
672
+ span ,
647
673
"try" ,
648
- try_hint ,
674
+ hint ,
649
675
Applicability :: MachineApplicable , // snippet
650
676
) ;
651
677
} ,
@@ -694,7 +720,7 @@ fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool {
694
720
}
695
721
}
696
722
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 < ' _ > ) {
698
724
if_chain ! {
699
725
if let TyKind :: Ptr ( ref mut_ty) = ty. kind;
700
726
if let ExprKind :: Lit ( ref lit) = e. kind;
0 commit comments