@@ -1496,16 +1496,31 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1496
1496
1497
1497
then {
1498
1498
if cx. access_levels. is_exported( impl_item. hir_id) {
1499
- // check missing trait implementations
1500
- for & ( method_name, n_args, fn_header, self_kind, out_type, trait_name) in & TRAIT_METHODS {
1501
- if name == method_name &&
1502
- sig. decl. inputs. len( ) == n_args &&
1503
- out_type. matches( cx, & sig. decl. output) &&
1504
- self_kind. matches( cx, self_ty, first_arg_ty) &&
1505
- fn_header_equals( * fn_header, sig. header) {
1506
- span_lint( cx, SHOULD_IMPLEMENT_TRAIT , impl_item. span, & format!(
1507
- "defining a method called `{}` on this type; consider implementing \
1508
- the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1499
+ // check missing trait implementations
1500
+ for method_config in & TRAIT_METHODS {
1501
+ if name == method_config. method_name &&
1502
+ sig. decl. inputs. len( ) == method_config. param_count &&
1503
+ method_config. output_type. matches( cx, & sig. decl. output) &&
1504
+ method_config. self_kind. matches( cx, self_ty, first_arg_ty) &&
1505
+ fn_header_equals( * method_config. fn_header, sig. header) &&
1506
+ method_config. lifetime_param_cond( & impl_item)
1507
+ {
1508
+ span_lint_and_help(
1509
+ cx,
1510
+ SHOULD_IMPLEMENT_TRAIT ,
1511
+ impl_item. span,
1512
+ & format!(
1513
+ "method `{}` can be confused for the standard trait method `{}::{}`" ,
1514
+ method_config. method_name,
1515
+ method_config. trait_name,
1516
+ method_config. method_name
1517
+ ) ,
1518
+ None ,
1519
+ & format!(
1520
+ "consider implementing the trait `{}` or choosing a less ambiguous method name" ,
1521
+ method_config. trait_name
1522
+ )
1523
+ ) ;
1509
1524
}
1510
1525
}
1511
1526
}
@@ -3390,38 +3405,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
3390
3405
abi : rustc_target:: spec:: abi:: Abi :: Rust ,
3391
3406
} ;
3392
3407
3408
+ struct ShouldImplTraitCase {
3409
+ trait_name : & ' static str ,
3410
+ method_name : & ' static str ,
3411
+ param_count : usize ,
3412
+ fn_header : & ' static hir:: FnHeader ,
3413
+ // implicit self kind expected (none, self, &self, ...)
3414
+ self_kind : SelfKind ,
3415
+ // checks against the output type
3416
+ output_type : OutType ,
3417
+ // certain methods with explicit lifetimes can't implement the equivalent trait method
3418
+ lint_explicit_lifetime : bool ,
3419
+ }
3420
+ impl ShouldImplTraitCase {
3421
+ const fn new (
3422
+ trait_name : & ' static str ,
3423
+ method_name : & ' static str ,
3424
+ param_count : usize ,
3425
+ fn_header : & ' static hir:: FnHeader ,
3426
+ self_kind : SelfKind ,
3427
+ output_type : OutType ,
3428
+ lint_explicit_lifetime : bool ,
3429
+ ) -> ShouldImplTraitCase {
3430
+ ShouldImplTraitCase {
3431
+ trait_name,
3432
+ method_name,
3433
+ param_count,
3434
+ fn_header,
3435
+ self_kind,
3436
+ output_type,
3437
+ lint_explicit_lifetime,
3438
+ }
3439
+ }
3440
+
3441
+ fn lifetime_param_cond ( & self , impl_item : & hir:: ImplItem < ' _ > ) -> bool {
3442
+ self . lint_explicit_lifetime
3443
+ || !impl_item. generics . params . iter ( ) . any ( |p| {
3444
+ matches ! (
3445
+ p. kind,
3446
+ hir:: GenericParamKind :: Lifetime {
3447
+ kind: hir:: LifetimeParamKind :: Explicit
3448
+ }
3449
+ )
3450
+ } )
3451
+ }
3452
+ }
3453
+
3393
3454
#[ rustfmt:: skip]
3394
- const TRAIT_METHODS : [ ( & str , usize , & hir:: FnHeader , SelfKind , OutType , & str ) ; 30 ] = [
3395
- ( "add" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Add" ) ,
3396
- ( "as_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::convert::AsMut" ) ,
3397
- ( "as_ref" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::convert::AsRef" ) ,
3398
- ( "bitand" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitAnd" ) ,
3399
- ( "bitor" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitOr" ) ,
3400
- ( "bitxor" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitXor" ) ,
3401
- ( "borrow" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::borrow::Borrow" ) ,
3402
- ( "borrow_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::borrow::BorrowMut" ) ,
3403
- ( "clone" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , "std::clone::Clone" ) ,
3404
- ( "cmp" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , "std::cmp::Ord" ) ,
3405
- ( "default" , 0 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::default::Default" ) ,
3406
- ( "deref" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::ops::Deref" ) ,
3407
- ( "deref_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::ops::DerefMut" ) ,
3408
- ( "div" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Div" ) ,
3409
- ( "drop" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Unit , "std::ops::Drop" ) ,
3410
- ( "eq" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Bool , "std::cmp::PartialEq" ) ,
3411
- ( "from_iter" , 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::iter::FromIterator" ) ,
3412
- ( "from_str" , 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::str::FromStr" ) ,
3413
- ( "hash" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Unit , "std::hash::Hash" ) ,
3414
- ( "index" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::ops::Index" ) ,
3415
- ( "index_mut" , 2 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::ops::IndexMut" ) ,
3416
- ( "into_iter" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::iter::IntoIterator" ) ,
3417
- ( "mul" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Mul" ) ,
3418
- ( "neg" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Neg" ) ,
3419
- ( "next" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Any , "std::iter::Iterator" ) ,
3420
- ( "not" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Not" ) ,
3421
- ( "rem" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Rem" ) ,
3422
- ( "shl" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Shl" ) ,
3423
- ( "shr" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Shr" ) ,
3424
- ( "sub" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Sub" ) ,
3455
+ const TRAIT_METHODS : [ ShouldImplTraitCase ; 30 ] = [
3456
+ ShouldImplTraitCase :: new ( "std::ops::Add" , "add" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3457
+ ShouldImplTraitCase :: new ( "std::convert::AsMut" , "as_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3458
+ ShouldImplTraitCase :: new ( "std::convert::AsRef" , "as_ref" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3459
+ ShouldImplTraitCase :: new ( "std::ops::BitAnd" , "bitand" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3460
+ ShouldImplTraitCase :: new ( "std::ops::BitOr" , "bitor" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3461
+ ShouldImplTraitCase :: new ( "std::ops::BitXor" , "bitxor" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3462
+ ShouldImplTraitCase :: new ( "std::borrow::Borrow" , "borrow" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3463
+ ShouldImplTraitCase :: new ( "std::borrow::BorrowMut" , "borrow_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3464
+ ShouldImplTraitCase :: new ( "std::clone::Clone" , "clone" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
3465
+ ShouldImplTraitCase :: new ( "std::cmp::Ord" , "cmp" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
3466
+ // FIXME: default doesn't work
3467
+ ShouldImplTraitCase :: new ( "std::default::Default" , "default" , 0 , & FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3468
+ ShouldImplTraitCase :: new ( "std::ops::Deref" , "deref" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3469
+ ShouldImplTraitCase :: new ( "std::ops::DerefMut" , "deref_mut" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3470
+ ShouldImplTraitCase :: new ( "std::ops::Div" , "div" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3471
+ ShouldImplTraitCase :: new ( "std::ops::Drop" , "drop" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Unit , true ) ,
3472
+ ShouldImplTraitCase :: new ( "std::cmp::PartialEq" , "eq" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Bool , true ) ,
3473
+ ShouldImplTraitCase :: new ( "std::iter::FromIterator" , "from_iter" , 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3474
+ ShouldImplTraitCase :: new ( "std::str::FromStr" , "from_str" , 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3475
+ ShouldImplTraitCase :: new ( "std::hash::Hash" , "hash" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Unit , true ) ,
3476
+ ShouldImplTraitCase :: new ( "std::ops::Index" , "index" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3477
+ ShouldImplTraitCase :: new ( "std::ops::IndexMut" , "index_mut" , 2 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3478
+ ShouldImplTraitCase :: new ( "std::iter::IntoIterator" , "into_iter" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3479
+ ShouldImplTraitCase :: new ( "std::ops::Mul" , "mul" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3480
+ ShouldImplTraitCase :: new ( "std::ops::Neg" , "neg" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3481
+ ShouldImplTraitCase :: new ( "std::iter::Iterator" , "next" , 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Any , false ) ,
3482
+ ShouldImplTraitCase :: new ( "std::ops::Not" , "not" , 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3483
+ ShouldImplTraitCase :: new ( "std::ops::Rem" , "rem" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3484
+ ShouldImplTraitCase :: new ( "std::ops::Shl" , "shl" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3485
+ ShouldImplTraitCase :: new ( "std::ops::Shr" , "shr" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3486
+ ShouldImplTraitCase :: new ( "std::ops::Sub" , "sub" , 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3425
3487
] ;
3426
3488
3427
3489
#[ rustfmt:: skip]
0 commit comments