@@ -1496,26 +1496,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
14961496
14971497 then {
14981498 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- let no_lifetime_params = || {
1502- !impl_item. generics. params. iter( )
1503- . any( |p| matches!(
1504- p. kind,
1505- hir:: GenericParamKind :: Lifetime { kind: hir:: LifetimeParamKind :: Explicit } ) )
1506- } ;
1507- if name == method_name &&
1508- sig. decl. inputs. len( ) == n_args &&
1509- out_type. matches( cx, & sig. decl. output) &&
1510- self_kind. matches( cx, self_ty, first_arg_ty) &&
1511- fn_header_equals( * fn_header, sig. header) &&
1512- // ignore methods with lifetime params, risk of false positive
1513- no_lifetime_params( )
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)
15141507 {
15151508 span_lint( cx, SHOULD_IMPLEMENT_TRAIT , impl_item. span, & format!(
15161509 "defining a method called `{}` on this type; consider implementing \
1517- the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1510+ the `{}` trait or choosing a less ambiguous name",
1511+ method_config. method_name, method_config. trait_name) ) ;
15181512 }
1513+
15191514 }
15201515 }
15211516
@@ -3398,39 +3393,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
33983393 abi : rustc_target:: spec:: abi:: Abi :: Rust ,
33993394} ;
34003395
3396+ struct ShouldImplTrait {
3397+ trait_name : & ' static str ,
3398+ method_name : & ' static str ,
3399+ param_count : usize ,
3400+ fn_header : & ' static hir:: FnHeader ,
3401+ // implicit self kind expected (none, self, &self, ...)
3402+ self_kind : SelfKind ,
3403+ // checks against the output type
3404+ output_type : OutType ,
3405+ // certain methods with explicit lifetimes can't implement the equivalent trait method
3406+ lint_explicit_lifetime : bool ,
3407+ }
3408+ impl ShouldImplTrait {
3409+ const fn new (
3410+ trait_name : & ' static str ,
3411+ method_name : & ' static str ,
3412+ param_count : usize ,
3413+ fn_header : & ' static hir:: FnHeader ,
3414+ self_kind : SelfKind ,
3415+ output_type : OutType ,
3416+ lint_explicit_lifetime : bool ,
3417+ ) -> ShouldImplTrait {
3418+ ShouldImplTrait {
3419+ trait_name,
3420+ method_name,
3421+ param_count,
3422+ fn_header,
3423+ self_kind,
3424+ output_type,
3425+ lint_explicit_lifetime,
3426+ }
3427+ }
3428+
3429+ fn lifetime_param_cond ( & self , impl_item : & hir:: ImplItem < ' _ > ) -> bool {
3430+ self . lint_explicit_lifetime
3431+ || !impl_item. generics . params . iter ( ) . any ( |p| {
3432+ matches ! (
3433+ p. kind,
3434+ hir:: GenericParamKind :: Lifetime {
3435+ kind: hir:: LifetimeParamKind :: Explicit
3436+ }
3437+ )
3438+ } )
3439+ }
3440+ }
3441+
34013442#[ rustfmt:: skip]
3402- const TRAIT_METHODS : [ ( & str , usize , & hir :: FnHeader , SelfKind , OutType , & str ) ; 30 ] = [
3403- ( " add", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Add" ) ,
3404- ( " as_mut", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::convert::AsMut" ) ,
3405- ( " as_ref", 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::convert::AsRef" ) ,
3406- ( " bitand", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitAnd" ) ,
3407- ( " bitor", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitOr" ) ,
3408- ( " bitxor", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::BitXor" ) ,
3409- ( " borrow", 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::borrow::Borrow" ) ,
3410- ( " borrow_mut", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::borrow::BorrowMut" ) ,
3411- ( " clone", 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , "std::clone::Clone" ) ,
3412- ( " cmp", 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , "std::cmp::Ord" ) ,
3443+ const TRAIT_METHODS : [ ShouldImplTrait ; 30 ] = [
3444+ ShouldImplTrait :: new ( "std::ops::Add" , " add", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3445+ ShouldImplTrait :: new ( "std::convert::AsMut" , " as_mut", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3446+ ShouldImplTrait :: new ( "std::convert::AsRef" , " as_ref", 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3447+ ShouldImplTrait :: new ( "std::ops::BitAnd" , " bitand", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3448+ ShouldImplTrait :: new ( "std::ops::BitOr" , " bitor", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3449+ ShouldImplTrait :: new ( "std::ops::BitXor" , " bitxor", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3450+ ShouldImplTrait :: new ( "std:: borrow::Borrow ", "borrow" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3451+ ShouldImplTrait :: new ( "std::borrow::BorrowMut" , " borrow_mut", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3452+ ShouldImplTrait :: new ( "std:: clone::Clone ", "clone" , 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
3453+ ShouldImplTrait :: new ( "std:: cmp::Ord ", "cmp" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Any , true ) ,
34133454 // FIXME: default doesn't work
3414- ( " default", 0 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::default::Default" ) ,
3415- ( " deref", 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::ops::Deref" ) ,
3416- ( " deref_mut", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::ops::DerefMut" ) ,
3417- ( " div", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Div" ) ,
3418- ( " drop", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Unit , "std::ops::Drop" ) ,
3419- ( " eq", 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Bool , "std::cmp::PartialEq" ) ,
3420- ( " from_iter", 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::iter::FromIterator" ) ,
3421- ( " from_str", 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , "std::str::FromStr" ) ,
3422- ( " hash", 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Unit , "std::hash::Hash" ) ,
3423- ( " index", 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , "std::ops::Index" ) ,
3424- ( " index_mut", 2 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , "std::ops::IndexMut" ) ,
3425- ( " into_iter", 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::iter::IntoIterator" ) ,
3426- ( " mul", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Mul" ) ,
3427- ( " neg", 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Neg" ) ,
3428- ( " next", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Any , "std::iter::Iterator" ) ,
3429- ( " not", 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Not" ) ,
3430- ( " rem", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Rem" ) ,
3431- ( " shl", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Shl" ) ,
3432- ( " shr", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Shr" ) ,
3433- ( " sub", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , "std::ops::Sub" ) ,
3455+ ShouldImplTrait :: new ( "std:: default::Default ", "default" , 0 , & FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3456+ ShouldImplTrait :: new ( "std::ops::Deref" , " deref", 1 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3457+ ShouldImplTrait :: new ( "std::ops::DerefMut" , " deref_mut", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3458+ ShouldImplTrait :: new ( "std::ops::Div" , " div", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3459+ ShouldImplTrait :: new ( "std::ops::Drop" , " drop", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Unit , true ) ,
3460+ ShouldImplTrait :: new ( "std::cmp::PartialEq" , " eq", 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Bool , true ) ,
3461+ ShouldImplTrait :: new ( "std::iter::FromIterator" , " from_iter", 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3462+ ShouldImplTrait :: new ( "std::str::FromStr" , " from_str", 1 , & FN_HEADER , SelfKind :: No , OutType :: Any , true ) ,
3463+ ShouldImplTrait :: new ( "std:: hash::Hash ", "hash" , 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Unit , true ) ,
3464+ ShouldImplTrait :: new ( "std::ops::Index" , " index", 2 , & FN_HEADER , SelfKind :: Ref , OutType :: Ref , true ) ,
3465+ ShouldImplTrait :: new ( "std::ops::IndexMut" , " index_mut", 2 , & FN_HEADER , SelfKind :: RefMut , OutType :: Ref , true ) ,
3466+ ShouldImplTrait :: new ( "std::iter::IntoIterator" , " into_iter", 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3467+ ShouldImplTrait :: new ( "std::ops::Mul" , " mul", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3468+ ShouldImplTrait :: new ( "std::ops::Neg" , " neg", 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3469+ ShouldImplTrait :: new ( "std::iter::Iterator" , " next", 1 , & FN_HEADER , SelfKind :: RefMut , OutType :: Any , false ) ,
3470+ ShouldImplTrait :: new ( "std::ops::Not" , " not", 1 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3471+ ShouldImplTrait :: new ( "std::ops::Rem" , " rem", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3472+ ShouldImplTrait :: new ( "std::ops::Shl" , " shl", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3473+ ShouldImplTrait :: new ( "std::ops::Shr" , " shr", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
3474+ ShouldImplTrait :: new ( "std::ops::Sub" , " sub", 2 , & FN_HEADER , SelfKind :: Value , OutType :: Any , true ) ,
34343475] ;
34353476
34363477#[ rustfmt:: skip]
0 commit comments