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