@@ -23,10 +23,10 @@ use crate::utils::sugg;
2323use crate :: utils:: usage:: mutated_variables;
2424use crate :: utils:: {
2525 get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
26- is_ctor_function, is_expn_of, is_self , is_self_ty , iter_input_pats, last_path_segment, match_def_path, match_path ,
27- match_qpath , match_trait_method , match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty,
28- same_tys , single_segment_path , snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
29- span_lint_and_sugg , span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq ,
26+ is_ctor_function, is_expn_of, iter_input_pats, last_path_segment, match_def_path, match_qpath , match_trait_method ,
27+ match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys , single_segment_path ,
28+ snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg ,
29+ span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq ,
3030} ;
3131
3232declare_clippy_lint ! {
@@ -1015,69 +1015,76 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
10151015 }
10161016 }
10171017
1018- fn check_impl_item ( & mut self , cx : & LateContext < ' a , ' tcx > , implitem : & ' tcx hir:: ImplItem ) {
1019- if in_external_macro ( cx. sess ( ) , implitem . span ) {
1018+ fn check_impl_item ( & mut self , cx : & LateContext < ' a , ' tcx > , impl_item : & ' tcx hir:: ImplItem ) {
1019+ if in_external_macro ( cx. sess ( ) , impl_item . span ) {
10201020 return ;
10211021 }
1022- let name = implitem . ident . name . as_str ( ) ;
1023- let parent = cx. tcx . hir ( ) . get_parent_item ( implitem . hir_id ) ;
1022+ let name = impl_item . ident . name . as_str ( ) ;
1023+ let parent = cx. tcx . hir ( ) . get_parent_item ( impl_item . hir_id ) ;
10241024 let item = cx. tcx . hir ( ) . expect_item ( parent) ;
10251025 let def_id = cx. tcx . hir ( ) . local_def_id ( item. hir_id ) ;
10261026 let ty = cx. tcx . type_of ( def_id) ;
10271027 if_chain ! {
1028- if let hir:: ImplItemKind :: Method ( ref sig, id) = implitem. node;
1029- if let Some ( first_arg_ty) = sig. decl. inputs. get( 0 ) ;
1028+ if let hir:: ImplItemKind :: Method ( ref sig, id) = impl_item. node;
10301029 if let Some ( first_arg) = iter_input_pats( & sig. decl, cx. tcx. hir( ) . body( id) ) . next( ) ;
1031- if let hir:: ItemKind :: Impl ( _, _, _, _, None , ref self_ty , _) = item. node;
1030+ if let hir:: ItemKind :: Impl ( _, _, _, _, None , _ , _) = item. node;
10321031 then {
1033- if cx. access_levels. is_exported( implitem. hir_id) {
1034- // check missing trait implementations
1035- for & ( method_name, n_args, self_kind, out_type, trait_name) in & TRAIT_METHODS {
1036- if name == method_name &&
1037- sig. decl. inputs. len( ) == n_args &&
1038- out_type. matches( cx, & sig. decl. output) &&
1039- self_kind. matches( cx, first_arg_ty, first_arg, self_ty, false , & implitem. generics) {
1040- span_lint( cx, SHOULD_IMPLEMENT_TRAIT , implitem. span, & format!(
1041- "defining a method called `{}` on this type; consider implementing \
1042- the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1043- }
1044- }
1045- }
1032+ let method_def_id = cx. tcx. hir( ) . local_def_id( impl_item. hir_id) ;
1033+ let method_sig = cx. tcx. fn_sig( method_def_id) ;
1034+ let method_sig = cx. tcx. erase_late_bound_regions( & method_sig) ;
1035+
1036+ let first_arg_ty = & method_sig. inputs( ) . iter( ) . next( ) ;
10461037
10471038 // check conventions w.r.t. conversion method names and predicates
1048- let is_copy = is_copy( cx, ty) ;
1049- for & ( ref conv, self_kinds) in & CONVENTIONS {
1050- if conv. check( & name) {
1051- if !self_kinds
1052- . iter( )
1053- . any( |k| k. matches( cx, first_arg_ty, first_arg, self_ty, is_copy, & implitem. generics) ) {
1054- let lint = if item. vis. node. is_pub( ) {
1055- WRONG_PUB_SELF_CONVENTION
1056- } else {
1057- WRONG_SELF_CONVENTION
1058- } ;
1059- span_lint( cx,
1060- lint,
1061- first_arg. pat. span,
1062- & format!( "methods called `{}` usually take {}; consider choosing a less \
1063- ambiguous name",
1064- conv,
1065- & self_kinds. iter( )
1066- . map( |k| k. description( ) )
1067- . collect:: <Vec <_>>( )
1068- . join( " or " ) ) ) ;
1039+ if let Some ( first_arg_ty) = first_arg_ty {
1040+
1041+ if cx. access_levels. is_exported( impl_item. hir_id) {
1042+ // check missing trait implementations
1043+ for & ( method_name, n_args, self_kind, out_type, trait_name) in & TRAIT_METHODS {
1044+ if name == method_name &&
1045+ sig. decl. inputs. len( ) == n_args &&
1046+ out_type. matches( cx, & sig. decl. output) &&
1047+ self_kind. matches( cx, ty, first_arg_ty) {
1048+ span_lint( cx, SHOULD_IMPLEMENT_TRAIT , impl_item. span, & format!(
1049+ "defining a method called `{}` on this type; consider implementing \
1050+ the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1051+ }
10691052 }
1053+ }
10701054
1071- // Only check the first convention to match (CONVENTIONS should be listed from most to least
1072- // specific)
1073- break ;
1055+ for & ( ref conv, self_kinds) in & CONVENTIONS {
1056+ if conv. check( & name) {
1057+ if !self_kinds
1058+ . iter( )
1059+ . any( |k| k. matches( cx, ty, first_arg_ty) ) {
1060+ let lint = if item. vis. node. is_pub( ) {
1061+ WRONG_PUB_SELF_CONVENTION
1062+ } else {
1063+ WRONG_SELF_CONVENTION
1064+ } ;
1065+ span_lint( cx,
1066+ lint,
1067+ first_arg. pat. span,
1068+ & format!( "methods called `{}` usually take {}; consider choosing a less \
1069+ ambiguous name",
1070+ conv,
1071+ & self_kinds. iter( )
1072+ . map( |k| k. description( ) )
1073+ . collect:: <Vec <_>>( )
1074+ . join( " or " ) ) ) ;
1075+ }
1076+
1077+ // Only check the first convention to match (CONVENTIONS should be listed from most to least
1078+ // specific)
1079+ break ;
1080+ }
10741081 }
10751082 }
10761083 }
10771084 }
10781085
1079- if let hir:: ImplItemKind :: Method ( _, _) = implitem . node {
1080- let ret_ty = return_ty ( cx, implitem . hir_id ) ;
1086+ if let hir:: ImplItemKind :: Method ( _, _) = impl_item . node {
1087+ let ret_ty = return_ty ( cx, impl_item . hir_id ) ;
10811088
10821089 // walk the return type and check for Self (this does not check associated types)
10831090 for inner_type in ret_ty. walk ( ) {
@@ -1111,7 +1118,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
11111118 span_lint (
11121119 cx,
11131120 NEW_RET_NO_SELF ,
1114- implitem . span ,
1121+ impl_item . span ,
11151122 "methods called `new` usually return `Self`" ,
11161123 ) ;
11171124 }
@@ -2614,55 +2621,49 @@ enum SelfKind {
26142621}
26152622
26162623impl SelfKind {
2617- fn matches (
2618- self ,
2619- cx : & LateContext < ' _ , ' _ > ,
2620- ty : & hir:: Ty ,
2621- arg : & hir:: Arg ,
2622- self_ty : & hir:: Ty ,
2623- allow_value_for_ref : bool ,
2624- generics : & hir:: Generics ,
2625- ) -> bool {
2626- // Self types in the HIR are desugared to explicit self types. So it will
2627- // always be `self:
2628- // SomeType`,
2629- // where SomeType can be `Self` or an explicit impl self type (e.g., `Foo` if
2630- // the impl is on `Foo`)
2631- // Thus, we only need to test equality against the impl self type or if it is
2632- // an explicit
2633- // `Self`. Furthermore, the only possible types for `self: ` are `&Self`,
2634- // `Self`, `&mut Self`,
2635- // and `Box<Self>`, including the equivalent types with `Foo`.
2636-
2637- let is_actually_self = |ty| is_self_ty ( ty) || SpanlessEq :: new ( cx) . eq_ty ( ty, self_ty) ;
2638- if is_self ( arg) {
2639- match self {
2640- Self :: Value => is_actually_self ( ty) ,
2641- Self :: Ref | Self :: RefMut => {
2642- if allow_value_for_ref && is_actually_self ( ty) {
2643- return true ;
2644- }
2645- match ty. node {
2646- hir:: TyKind :: Rptr ( _, ref mt_ty) => {
2647- let mutability_match = if self == Self :: Ref {
2648- mt_ty. mutbl == hir:: MutImmutable
2649- } else {
2650- mt_ty. mutbl == hir:: MutMutable
2651- } ;
2652- is_actually_self ( & mt_ty. ty ) && mutability_match
2653- } ,
2654- _ => false ,
2655- }
2656- } ,
2657- _ => false ,
2624+ fn matches < ' a > ( self , cx : & LateContext < ' _ , ' a > , parent_ty : Ty < ' a > , ty : Ty < ' a > ) -> bool {
2625+ fn matches_value ( parent_ty : Ty < ' _ > , ty : Ty < ' _ > ) -> bool {
2626+ if ty == parent_ty {
2627+ true
2628+ } else if ty. is_box ( ) {
2629+ ty. boxed_ty ( ) == parent_ty
2630+ } else if ty. is_rc ( ) || ty. is_arc ( ) {
2631+ if let ty:: Adt ( _, substs) = ty. sty {
2632+ substs. types ( ) . next ( ) . map_or ( false , |t| t == parent_ty)
2633+ } else {
2634+ false
2635+ }
2636+ } else {
2637+ false
26582638 }
2659- } else {
2660- match self {
2661- Self :: Value => false ,
2662- Self :: Ref => is_as_ref_or_mut_trait ( ty, self_ty, generics, & paths:: ASREF_TRAIT ) ,
2663- Self :: RefMut => is_as_ref_or_mut_trait ( ty, self_ty, generics, & paths:: ASMUT_TRAIT ) ,
2664- Self :: No => true ,
2639+ }
2640+
2641+ fn matches_ref < ' a > (
2642+ cx : & LateContext < ' _ , ' a > ,
2643+ mutability : hir:: Mutability ,
2644+ parent_ty : Ty < ' a > ,
2645+ ty : Ty < ' a > ,
2646+ ) -> bool {
2647+ if let ty:: Ref ( _, t, m) = ty. sty {
2648+ return m == mutability && t == parent_ty;
26652649 }
2650+
2651+ let trait_path = match mutability {
2652+ hir:: Mutability :: MutImmutable => & paths:: ASREF_TRAIT ,
2653+ hir:: Mutability :: MutMutable => & paths:: ASMUT_TRAIT ,
2654+ } ;
2655+
2656+ let trait_def_id = get_trait_def_id ( cx, trait_path) . expect ( "trait def id not found" ) ;
2657+ implements_trait ( cx, ty, trait_def_id, & [ parent_ty. into ( ) ] )
2658+ }
2659+
2660+ match self {
2661+ Self :: Value => matches_value ( parent_ty, ty) ,
2662+ Self :: Ref => {
2663+ matches_ref ( cx, hir:: Mutability :: MutImmutable , parent_ty, ty) || ty == parent_ty && is_copy ( cx, ty)
2664+ } ,
2665+ Self :: RefMut => matches_ref ( cx, hir:: Mutability :: MutMutable , parent_ty, ty) ,
2666+ Self :: No => ty != parent_ty,
26662667 }
26672668 }
26682669
@@ -2676,68 +2677,6 @@ impl SelfKind {
26762677 }
26772678}
26782679
2679- fn is_as_ref_or_mut_trait ( ty : & hir:: Ty , self_ty : & hir:: Ty , generics : & hir:: Generics , name : & [ & str ] ) -> bool {
2680- single_segment_ty ( ty) . map_or ( false , |seg| {
2681- generics. params . iter ( ) . any ( |param| match param. kind {
2682- hir:: GenericParamKind :: Type { .. } => {
2683- param. name . ident ( ) . name == seg. ident . name
2684- && param. bounds . iter ( ) . any ( |bound| {
2685- if let hir:: GenericBound :: Trait ( ref ptr, ..) = * bound {
2686- let path = & ptr. trait_ref . path ;
2687- match_path ( path, name)
2688- && path. segments . last ( ) . map_or ( false , |s| {
2689- if let Some ( ref params) = s. args {
2690- if params. parenthesized {
2691- false
2692- } else {
2693- // FIXME(flip1995): messy, improve if there is a better option
2694- // in the compiler
2695- let types: Vec < _ > = params
2696- . args
2697- . iter ( )
2698- . filter_map ( |arg| match arg {
2699- hir:: GenericArg :: Type ( ty) => Some ( ty) ,
2700- _ => None ,
2701- } )
2702- . collect ( ) ;
2703- types. len ( ) == 1 && ( is_self_ty ( & types[ 0 ] ) || is_ty ( & * types[ 0 ] , self_ty) )
2704- }
2705- } else {
2706- false
2707- }
2708- } )
2709- } else {
2710- false
2711- }
2712- } )
2713- } ,
2714- _ => false ,
2715- } )
2716- } )
2717- }
2718-
2719- fn is_ty ( ty : & hir:: Ty , self_ty : & hir:: Ty ) -> bool {
2720- match ( & ty. node , & self_ty. node ) {
2721- (
2722- & hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref ty_path) ) ,
2723- & hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref self_ty_path) ) ,
2724- ) => ty_path
2725- . segments
2726- . iter ( )
2727- . map ( |seg| seg. ident . name )
2728- . eq ( self_ty_path. segments . iter ( ) . map ( |seg| seg. ident . name ) ) ,
2729- _ => false ,
2730- }
2731- }
2732-
2733- fn single_segment_ty ( ty : & hir:: Ty ) -> Option < & hir:: PathSegment > {
2734- if let hir:: TyKind :: Path ( ref path) = ty. node {
2735- single_segment_path ( path)
2736- } else {
2737- None
2738- }
2739- }
2740-
27412680impl Convention {
27422681 fn check ( & self , other : & str ) -> bool {
27432682 match * self {
0 commit comments