@@ -23,10 +23,10 @@ use crate::utils::sugg;
23
23
use crate :: utils:: usage:: mutated_variables;
24
24
use crate :: utils:: {
25
25
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 ,
30
30
} ;
31
31
32
32
declare_clippy_lint ! {
@@ -1002,51 +1002,58 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
1002
1002
let ty = cx. tcx . type_of ( def_id) ;
1003
1003
if_chain ! {
1004
1004
if let hir:: ImplItemKind :: Method ( ref sig, id) = impl_item. node;
1005
- if let Some ( first_arg_ty) = sig. decl. inputs. get( 0 ) ;
1006
1005
if let Some ( first_arg) = iter_input_pats( & sig. decl, cx. tcx. hir( ) . body( id) ) . next( ) ;
1007
- if let hir:: ItemKind :: Impl ( _, _, _, _, None , ref self_ty , _) = item. node;
1006
+ if let hir:: ItemKind :: Impl ( _, _, _, _, None , _ , _) = item. node;
1008
1007
then {
1009
- if cx. access_levels. is_exported( impl_item. hir_id) {
1010
- // check missing trait implementations
1011
- for & ( method_name, n_args, self_kind, out_type, trait_name) in & TRAIT_METHODS {
1012
- if name == method_name &&
1013
- sig. decl. inputs. len( ) == n_args &&
1014
- out_type. matches( cx, & sig. decl. output) &&
1015
- self_kind. matches( cx, first_arg_ty, first_arg, self_ty, false , & impl_item. generics) {
1016
- span_lint( cx, SHOULD_IMPLEMENT_TRAIT , impl_item. span, & format!(
1017
- "defining a method called `{}` on this type; consider implementing \
1018
- the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1019
- }
1020
- }
1021
- }
1008
+ let method_def_id = cx. tcx. hir( ) . local_def_id( impl_item. hir_id) ;
1009
+ let method_sig = cx. tcx. fn_sig( method_def_id) ;
1010
+ let method_sig = cx. tcx. erase_late_bound_regions( & method_sig) ;
1011
+
1012
+ let first_arg_ty = & method_sig. inputs( ) . iter( ) . next( ) ;
1022
1013
1023
1014
// check conventions w.r.t. conversion method names and predicates
1024
- let is_copy = is_copy( cx, ty) ;
1025
- for & ( ref conv, self_kinds) in & CONVENTIONS {
1026
- if conv. check( & name) {
1027
- if !self_kinds
1028
- . iter( )
1029
- . any( |k| k. matches( cx, first_arg_ty, first_arg, self_ty, is_copy, & impl_item. generics) ) {
1030
- let lint = if item. vis. node. is_pub( ) {
1031
- WRONG_PUB_SELF_CONVENTION
1032
- } else {
1033
- WRONG_SELF_CONVENTION
1034
- } ;
1035
- span_lint( cx,
1036
- lint,
1037
- first_arg. pat. span,
1038
- & format!( "methods called `{}` usually take {}; consider choosing a less \
1039
- ambiguous name",
1040
- conv,
1041
- & self_kinds. iter( )
1042
- . map( |k| k. description( ) )
1043
- . collect:: <Vec <_>>( )
1044
- . join( " or " ) ) ) ;
1015
+ if let Some ( first_arg_ty) = first_arg_ty {
1016
+
1017
+ if cx. access_levels. is_exported( impl_item. hir_id) {
1018
+ // check missing trait implementations
1019
+ for & ( method_name, n_args, self_kind, out_type, trait_name) in & TRAIT_METHODS {
1020
+ if name == method_name &&
1021
+ sig. decl. inputs. len( ) == n_args &&
1022
+ out_type. matches( cx, & sig. decl. output) &&
1023
+ self_kind. matches( cx, ty, first_arg_ty) {
1024
+ span_lint( cx, SHOULD_IMPLEMENT_TRAIT , impl_item. span, & format!(
1025
+ "defining a method called `{}` on this type; consider implementing \
1026
+ the `{}` trait or choosing a less ambiguous name", name, trait_name) ) ;
1027
+ }
1045
1028
}
1029
+ }
1046
1030
1047
- // Only check the first convention to match (CONVENTIONS should be listed from most to least
1048
- // specific)
1049
- break ;
1031
+ for & ( ref conv, self_kinds) in & CONVENTIONS {
1032
+ if conv. check( & name) {
1033
+ if !self_kinds
1034
+ . iter( )
1035
+ . any( |k| k. matches( cx, ty, first_arg_ty) ) {
1036
+ let lint = if item. vis. node. is_pub( ) {
1037
+ WRONG_PUB_SELF_CONVENTION
1038
+ } else {
1039
+ WRONG_SELF_CONVENTION
1040
+ } ;
1041
+ span_lint( cx,
1042
+ lint,
1043
+ first_arg. pat. span,
1044
+ & format!( "methods called `{}` usually take {}; consider choosing a less \
1045
+ ambiguous name",
1046
+ conv,
1047
+ & self_kinds. iter( )
1048
+ . map( |k| k. description( ) )
1049
+ . collect:: <Vec <_>>( )
1050
+ . join( " or " ) ) ) ;
1051
+ }
1052
+
1053
+ // Only check the first convention to match (CONVENTIONS should be listed from most to least
1054
+ // specific)
1055
+ break ;
1056
+ }
1050
1057
}
1051
1058
}
1052
1059
}
@@ -2539,55 +2546,33 @@ enum SelfKind {
2539
2546
}
2540
2547
2541
2548
impl SelfKind {
2542
- fn matches (
2543
- self ,
2544
- cx : & LateContext < ' _ , ' _ > ,
2545
- ty : & hir:: Ty ,
2546
- arg : & hir:: Arg ,
2547
- self_ty : & hir:: Ty ,
2548
- allow_value_for_ref : bool ,
2549
- generics : & hir:: Generics ,
2550
- ) -> bool {
2551
- // Self types in the HIR are desugared to explicit self types. So it will
2552
- // always be `self:
2553
- // SomeType`,
2554
- // where SomeType can be `Self` or an explicit impl self type (e.g., `Foo` if
2555
- // the impl is on `Foo`)
2556
- // Thus, we only need to test equality against the impl self type or if it is
2557
- // an explicit
2558
- // `Self`. Furthermore, the only possible types for `self: ` are `&Self`,
2559
- // `Self`, `&mut Self`,
2560
- // and `Box<Self>`, including the equivalent types with `Foo`.
2561
-
2562
- let is_actually_self = |ty| is_self_ty ( ty) || SpanlessEq :: new ( cx) . eq_ty ( ty, self_ty) ;
2563
- if is_self ( arg) {
2564
- match self {
2565
- Self :: Value => is_actually_self ( ty) ,
2566
- Self :: Ref | Self :: RefMut => {
2567
- if allow_value_for_ref && is_actually_self ( ty) {
2568
- return true ;
2569
- }
2570
- match ty. node {
2571
- hir:: TyKind :: Rptr ( _, ref mt_ty) => {
2572
- let mutability_match = if self == Self :: Ref {
2573
- mt_ty. mutbl == hir:: MutImmutable
2574
- } else {
2575
- mt_ty. mutbl == hir:: MutMutable
2576
- } ;
2577
- is_actually_self ( & mt_ty. ty ) && mutability_match
2578
- } ,
2579
- _ => false ,
2580
- }
2581
- } ,
2582
- _ => false ,
2583
- }
2584
- } else {
2585
- match self {
2586
- Self :: Value => false ,
2587
- Self :: Ref => is_as_ref_or_mut_trait ( ty, self_ty, generics, & paths:: ASREF_TRAIT ) ,
2588
- Self :: RefMut => is_as_ref_or_mut_trait ( ty, self_ty, generics, & paths:: ASMUT_TRAIT ) ,
2589
- Self :: No => true ,
2549
+ fn matches < ' a > ( self , cx : & LateContext < ' _ , ' a > , parent_ty : Ty < ' a > , ty : Ty < ' a > ) -> bool {
2550
+ fn matches_ref < ' a > (
2551
+ cx : & LateContext < ' _ , ' a > ,
2552
+ mutability : hir:: Mutability ,
2553
+ parent_ty : Ty < ' a > ,
2554
+ ty : Ty < ' a > ,
2555
+ ) -> bool {
2556
+ if let ty:: Ref ( _, t, m) = ty. sty {
2557
+ return m == mutability && t == parent_ty;
2590
2558
}
2559
+
2560
+ let trait_path = match mutability {
2561
+ hir:: Mutability :: MutImmutable => & paths:: ASREF_TRAIT ,
2562
+ hir:: Mutability :: MutMutable => & paths:: ASMUT_TRAIT ,
2563
+ } ;
2564
+
2565
+ let trait_def_id = get_trait_def_id ( cx, trait_path) . expect ( "trait def id not found" ) ;
2566
+ implements_trait ( cx, ty, trait_def_id, & [ parent_ty. into ( ) ] )
2567
+ }
2568
+
2569
+ match self {
2570
+ Self :: Value => ty == parent_ty,
2571
+ Self :: Ref => {
2572
+ matches_ref ( cx, hir:: Mutability :: MutImmutable , parent_ty, ty) || ty == parent_ty && is_copy ( cx, ty)
2573
+ } ,
2574
+ Self :: RefMut => matches_ref ( cx, hir:: Mutability :: MutMutable , parent_ty, ty) ,
2575
+ Self :: No => ty != parent_ty,
2591
2576
}
2592
2577
}
2593
2578
@@ -2601,68 +2586,6 @@ impl SelfKind {
2601
2586
}
2602
2587
}
2603
2588
2604
- fn is_as_ref_or_mut_trait ( ty : & hir:: Ty , self_ty : & hir:: Ty , generics : & hir:: Generics , name : & [ & str ] ) -> bool {
2605
- single_segment_ty ( ty) . map_or ( false , |seg| {
2606
- generics. params . iter ( ) . any ( |param| match param. kind {
2607
- hir:: GenericParamKind :: Type { .. } => {
2608
- param. name . ident ( ) . name == seg. ident . name
2609
- && param. bounds . iter ( ) . any ( |bound| {
2610
- if let hir:: GenericBound :: Trait ( ref ptr, ..) = * bound {
2611
- let path = & ptr. trait_ref . path ;
2612
- match_path ( path, name)
2613
- && path. segments . last ( ) . map_or ( false , |s| {
2614
- if let Some ( ref params) = s. args {
2615
- if params. parenthesized {
2616
- false
2617
- } else {
2618
- // FIXME(flip1995): messy, improve if there is a better option
2619
- // in the compiler
2620
- let types: Vec < _ > = params
2621
- . args
2622
- . iter ( )
2623
- . filter_map ( |arg| match arg {
2624
- hir:: GenericArg :: Type ( ty) => Some ( ty) ,
2625
- _ => None ,
2626
- } )
2627
- . collect ( ) ;
2628
- types. len ( ) == 1 && ( is_self_ty ( & types[ 0 ] ) || is_ty ( & * types[ 0 ] , self_ty) )
2629
- }
2630
- } else {
2631
- false
2632
- }
2633
- } )
2634
- } else {
2635
- false
2636
- }
2637
- } )
2638
- } ,
2639
- _ => false ,
2640
- } )
2641
- } )
2642
- }
2643
-
2644
- fn is_ty ( ty : & hir:: Ty , self_ty : & hir:: Ty ) -> bool {
2645
- match ( & ty. node , & self_ty. node ) {
2646
- (
2647
- & hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref ty_path) ) ,
2648
- & hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref self_ty_path) ) ,
2649
- ) => ty_path
2650
- . segments
2651
- . iter ( )
2652
- . map ( |seg| seg. ident . name )
2653
- . eq ( self_ty_path. segments . iter ( ) . map ( |seg| seg. ident . name ) ) ,
2654
- _ => false ,
2655
- }
2656
- }
2657
-
2658
- fn single_segment_ty ( ty : & hir:: Ty ) -> Option < & hir:: PathSegment > {
2659
- if let hir:: TyKind :: Path ( ref path) = ty. node {
2660
- single_segment_path ( path)
2661
- } else {
2662
- None
2663
- }
2664
- }
2665
-
2666
2589
impl Convention {
2667
2590
fn check ( & self , other : & str ) -> bool {
2668
2591
match * self {
0 commit comments