@@ -1500,6 +1500,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1500
1500
}
1501
1501
}
1502
1502
1503
+ #[ allow( clippy:: too_many_lines) ]
1503
1504
fn check_impl_item ( & mut self , cx : & LateContext < ' tcx > , impl_item : & ' tcx hir:: ImplItem < ' _ > ) {
1504
1505
if in_external_macro ( cx. sess ( ) , impl_item. span ) {
1505
1506
return ;
@@ -1525,16 +1526,31 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1525
1526
1526
1527
then {
1527
1528
if cx. access_levels. is_exported( impl_item. hir_id) {
1528
- // check missing trait implementations
1529
- for & ( method_name, n_args, fn_header, self_kind, out_type, trait_name) in & TRAIT_METHODS {
1530
- if name == method_name &&
1531
- sig. decl. inputs. len( ) == n_args &&
1532
- out_type. matches( cx, & sig. decl. output) &&
1533
- self_kind. matches( cx, self_ty, first_arg_ty) &&
1534
- fn_header_equals( * fn_header, sig. header) {
1535
- span_lint( cx, SHOULD_IMPLEMENT_TRAIT , impl_item. span, & format!(
1536
- "defining a method called `{}` on this type; consider implementing \
1537
- the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1529
+ // check missing trait implementations
1530
+ for method_config in & TRAIT_METHODS {
1531
+ if name == method_config. method_name &&
1532
+ sig. decl. inputs. len( ) == method_config. param_count &&
1533
+ method_config. output_type. matches( cx, & sig. decl. output) &&
1534
+ method_config. self_kind. matches( cx, self_ty, first_arg_ty) &&
1535
+ fn_header_equals( method_config. fn_header, sig. header) &&
1536
+ method_config. lifetime_param_cond( & impl_item)
1537
+ {
1538
+ span_lint_and_help(
1539
+ cx,
1540
+ SHOULD_IMPLEMENT_TRAIT ,
1541
+ impl_item. span,
1542
+ & format!(
1543
+ "method `{}` can be confused for the standard trait method `{}::{}`" ,
1544
+ method_config. method_name,
1545
+ method_config. trait_name,
1546
+ method_config. method_name
1547
+ ) ,
1548
+ None ,
1549
+ & format!(
1550
+ "consider implementing the trait `{}` or choosing a less ambiguous method name" ,
1551
+ method_config. trait_name
1552
+ )
1553
+ ) ;
1538
1554
}
1539
1555
}
1540
1556
}
@@ -3464,38 +3480,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
3464
3480
abi : rustc_target:: spec:: abi:: Abi :: Rust ,
3465
3481
} ;
3466
3482
3483
+ struct ShouldImplTraitCase {
3484
+ trait_name : & ' static str ,
3485
+ method_name : & ' static str ,
3486
+ param_count : usize ,
3487
+ fn_header : hir:: FnHeader ,
3488
+ // implicit self kind expected (none, self, &self, ...)
3489
+ self_kind : SelfKind ,
3490
+ // checks against the output type
3491
+ output_type : OutType ,
3492
+ // certain methods with explicit lifetimes can't implement the equivalent trait method
3493
+ lint_explicit_lifetime : bool ,
3494
+ }
3495
+ impl ShouldImplTraitCase {
3496
+ const fn new (
3497
+ trait_name : & ' static str ,
3498
+ method_name : & ' static str ,
3499
+ param_count : usize ,
3500
+ fn_header : hir:: FnHeader ,
3501
+ self_kind : SelfKind ,
3502
+ output_type : OutType ,
3503
+ lint_explicit_lifetime : bool ,
3504
+ ) -> ShouldImplTraitCase {
3505
+ ShouldImplTraitCase {
3506
+ trait_name,
3507
+ method_name,
3508
+ param_count,
3509
+ fn_header,
3510
+ self_kind,
3511
+ output_type,
3512
+ lint_explicit_lifetime,
3513
+ }
3514
+ }
3515
+
3516
+ fn lifetime_param_cond ( & self , impl_item : & hir:: ImplItem < ' _ > ) -> bool {
3517
+ self . lint_explicit_lifetime
3518
+ || !impl_item. generics . params . iter ( ) . any ( |p| {
3519
+ matches ! (
3520
+ p. kind,
3521
+ hir:: GenericParamKind :: Lifetime {
3522
+ kind: hir:: LifetimeParamKind :: Explicit
3523
+ }
3524
+ )
3525
+ } )
3526
+ }
3527
+ }
3528
+
3467
3529
#[ rustfmt:: skip]
3468
- const TRAIT_METHODS : [ ( & str , usize , & hir:: FnHeader , SelfKind , OutType , & str ) ; 30 ] = [
3469
- ( "add" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Add" ) ,
3470
- ( "as_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::convert::AsMut" ) ,
3471
- ( "as_ref" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::convert::AsRef" ) ,
3472
- ( "bitand" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitAnd" ) ,
3473
- ( "bitor" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitOr" ) ,
3474
- ( "bitxor" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitXor" ) ,
3475
- ( "borrow" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::borrow::Borrow" ) ,
3476
- ( "borrow_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::borrow::BorrowMut" ) ,
3477
- ( "clone" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , "std::clone::Clone" ) ,
3478
- ( "cmp" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , "std::cmp::Ord" ) ,
3479
- ( "default" , 0 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::default::Default" ) ,
3480
- ( "deref" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::ops::Deref" ) ,
3481
- ( "deref_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::ops::DerefMut" ) ,
3482
- ( "div" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Div" ) ,
3483
- ( "drop" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Unit , "std::ops::Drop" ) ,
3484
- ( "eq" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Bool , "std::cmp::PartialEq" ) ,
3485
- ( "from_iter" , 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::iter::FromIterator" ) ,
3486
- ( "from_str" , 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::str::FromStr" ) ,
3487
- ( "hash" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Unit , "std::hash::Hash" ) ,
3488
- ( "index" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::ops::Index" ) ,
3489
- ( "index_mut" , 2 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::ops::IndexMut" ) ,
3490
- ( "into_iter" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::iter::IntoIterator" ) ,
3491
- ( "mul" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Mul" ) ,
3492
- ( "neg" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Neg" ) ,
3493
- ( "next" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Any , "std::iter::Iterator" ) ,
3494
- ( "not" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Not" ) ,
3495
- ( "rem" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Rem" ) ,
3496
- ( "shl" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Shl" ) ,
3497
- ( "shr" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Shr" ) ,
3498
- ( "sub" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Sub" ) ,
3530
+ const TRAIT_METHODS : [ ShouldImplTraitCase ; 30 ] = [
3531
+ ShouldImplTraitCase :: new ( "std::ops::Add" , "add" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3532
+ ShouldImplTraitCase :: new ( "std::convert::AsMut" , "as_mut" , 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3533
+ ShouldImplTraitCase :: new ( "std::convert::AsRef" , "as_ref" , 1 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3534
+ ShouldImplTraitCase :: new ( "std::ops::BitAnd" , "bitand" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3535
+ ShouldImplTraitCase :: new ( "std::ops::BitOr" , "bitor" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3536
+ ShouldImplTraitCase :: new ( "std::ops::BitXor" , "bitxor" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3537
+ ShouldImplTraitCase :: new ( "std::borrow::Borrow" , "borrow" , 1 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3538
+ ShouldImplTraitCase :: new ( "std::borrow::BorrowMut" , "borrow_mut" , 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3539
+ ShouldImplTraitCase :: new ( "std::clone::Clone" , "clone" , 1 , FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
3540
+ ShouldImplTraitCase :: new ( "std::cmp::Ord" , "cmp" , 2 , FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
3541
+ // FIXME: default doesn't work
3542
+ ShouldImplTraitCase :: new ( "std::default::Default" , "default" , 0 , FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3543
+ ShouldImplTraitCase :: new ( "std::ops::Deref" , "deref" , 1 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3544
+ ShouldImplTraitCase :: new ( "std::ops::DerefMut" , "deref_mut" , 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3545
+ ShouldImplTraitCase :: new ( "std::ops::Div" , "div" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3546
+ ShouldImplTraitCase :: new ( "std::ops::Drop" , "drop" , 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Unit , true ) ,
3547
+ ShouldImplTraitCase :: new ( "std::cmp::PartialEq" , "eq" , 2 , FN_HEADER , SelfKind :: Ref , OutType :: Bool , true ) ,
3548
+ ShouldImplTraitCase :: new ( "std::iter::FromIterator" , "from_iter" , 1 , FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3549
+ ShouldImplTraitCase :: new ( "std::str::FromStr" , "from_str" , 1 , FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3550
+ ShouldImplTraitCase :: new ( "std::hash::Hash" , "hash" , 2 , FN_HEADER , SelfKind :: Ref , OutType :: Unit , true ) ,
3551
+ ShouldImplTraitCase :: new ( "std::ops::Index" , "index" , 2 , FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3552
+ ShouldImplTraitCase :: new ( "std::ops::IndexMut" , "index_mut" , 2 , FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3553
+ ShouldImplTraitCase :: new ( "std::iter::IntoIterator" , "into_iter" , 1 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3554
+ ShouldImplTraitCase :: new ( "std::ops::Mul" , "mul" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3555
+ ShouldImplTraitCase :: new ( "std::ops::Neg" , "neg" , 1 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3556
+ ShouldImplTraitCase :: new ( "std::iter::Iterator" , "next" , 1 , FN_HEADER , SelfKind :: RefMut , OutType :: Any , false ) ,
3557
+ ShouldImplTraitCase :: new ( "std::ops::Not" , "not" , 1 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3558
+ ShouldImplTraitCase :: new ( "std::ops::Rem" , "rem" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3559
+ ShouldImplTraitCase :: new ( "std::ops::Shl" , "shl" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3560
+ ShouldImplTraitCase :: new ( "std::ops::Shr" , "shr" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3561
+ ShouldImplTraitCase :: new ( "std::ops::Sub" , "sub" , 2 , FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3499
3562
] ;
3500
3563
3501
3564
#[ rustfmt:: skip]
0 commit comments