@@ -38,73 +38,87 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
38
38
39
39
impl < ' tcx > LateLintPass < ' tcx > for NoopMethodCall {
40
40
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
41
- // We only care about method calls
42
- if let ExprKind :: MethodCall ( call, _, elements, _) = expr. kind {
43
- // Get the `DefId` only when dealing with an `AssocFn`
44
- if let Some ( ( DefKind :: AssocFn , did) ) =
45
- cx. typeck_results ( ) . type_dependent_def ( expr. hir_id )
46
- {
47
- // Check that we're dealing with a trait method
48
- if let Some ( trait_id) = cx. tcx . trait_of_item ( did) {
49
- // Check we're dealing with one of the traits we care about
50
- if ![ sym:: Clone , sym:: Deref , sym:: Borrow ]
41
+ // We only care about method calls.
42
+ let ( call, elements) = match expr. kind {
43
+ ExprKind :: MethodCall ( call, _, elements, _) => ( call, elements) ,
44
+ _ => return ,
45
+ } ;
46
+ // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
47
+ // traits and ignore any other method call.
48
+ let ( trait_id, did) = match cx. typeck_results ( ) . type_dependent_def ( expr. hir_id ) {
49
+ // Verify we are dealing with a method/associated function.
50
+ Some ( ( DefKind :: AssocFn , did) ) => match cx. tcx . trait_of_item ( did) {
51
+ // Check that we're dealing with a trait method for one of the traits we care about.
52
+ Some ( trait_id)
53
+ if [ sym:: Clone , sym:: Deref , sym:: Borrow ]
51
54
. iter ( )
52
- . any ( |s| cx. tcx . is_diagnostic_item ( * s, trait_id) )
53
- {
54
- return ;
55
- }
56
-
57
- let substs = cx. typeck_results ( ) . node_substs ( expr. hir_id ) ;
58
- // We can't resolve on types that require monomorphization,
59
- // so check that we don't need to perfom substitution
60
- if !substs. needs_subst ( ) {
61
- let param_env = cx. tcx . param_env ( trait_id) ;
62
- // Resolve the trait method instance
63
- if let Ok ( Some ( i) ) = ty:: Instance :: resolve ( cx. tcx , param_env, did, substs) {
64
- // Check that it implements the noop diagnostic
65
- for ( s, peel_ref) in [
66
- ( sym:: noop_method_borrow, true ) ,
67
- ( sym:: noop_method_clone, false ) ,
68
- ( sym:: noop_method_deref, true ) ,
69
- ]
70
- . iter ( )
71
- {
72
- if cx. tcx . is_diagnostic_item ( * s, i. def_id ( ) ) {
73
- let method = & call. ident . name ;
74
- let receiver = & elements[ 0 ] ;
75
- let receiver_ty = cx. typeck_results ( ) . expr_ty ( receiver) ;
76
- let receiver_ty = match receiver_ty. kind ( ) {
77
- // Remove one borrow from the receiver as all the trait methods
78
- // we care about here have a `&self` receiver.
79
- ty:: Ref ( _, ty, _) if * peel_ref => ty,
80
- _ => receiver_ty,
81
- } ;
82
- let expr_ty = cx. typeck_results ( ) . expr_ty_adjusted ( expr) ;
83
- if receiver_ty != expr_ty {
84
- return ;
85
- }
86
- let expr_span = expr. span ;
87
- let note = format ! (
88
- "the type `{:?}` which `{}` is being called on is the same as \
89
- the type returned from `{}`, so the method call does not do \
90
- anything and can be removed",
91
- receiver_ty, method, method,
92
- ) ;
93
-
94
- let span = expr_span. with_lo ( receiver. span . hi ( ) ) ;
95
- cx. struct_span_lint ( NOOP_METHOD_CALL , span, |lint| {
96
- let method = & call. ident . name ;
97
- let message = format ! ( "call to `.{}()` on a reference in this situation does nothing" , & method) ;
98
- lint. build ( & message)
99
- . span_label ( span, "unnecessary method call" )
100
- . note ( & note)
101
- . emit ( )
102
- } ) ;
103
- }
104
- }
105
- }
106
- }
55
+ . any ( |s| cx. tcx . is_diagnostic_item ( * s, trait_id) ) =>
56
+ {
57
+ ( trait_id, did)
107
58
}
59
+ _ => return ,
60
+ } ,
61
+ _ => return ,
62
+ } ;
63
+ let substs = cx. typeck_results ( ) . node_substs ( expr. hir_id ) ;
64
+ if substs. needs_subst ( ) {
65
+ // We can't resolve on types that require monomorphization, so we don't handle them if
66
+ // we need to perfom substitution.
67
+ return ;
68
+ }
69
+ let param_env = cx. tcx . param_env ( trait_id) ;
70
+ // Resolve the trait method instance.
71
+ let i = match ty:: Instance :: resolve ( cx. tcx , param_env, did, substs) {
72
+ Ok ( Some ( i) ) => i,
73
+ _ => return ,
74
+ } ;
75
+ // (Re)check that it implements the noop diagnostic.
76
+ for ( s, peel_ref) in [
77
+ ( sym:: noop_method_borrow, true ) ,
78
+ ( sym:: noop_method_clone, false ) ,
79
+ ( sym:: noop_method_deref, true ) ,
80
+ ]
81
+ . iter ( )
82
+ {
83
+ if cx. tcx . is_diagnostic_item ( * s, i. def_id ( ) ) {
84
+ let method = & call. ident . name ;
85
+ let receiver = & elements[ 0 ] ;
86
+ let receiver_ty = cx. typeck_results ( ) . expr_ty ( receiver) ;
87
+ let receiver_ty = match receiver_ty. kind ( ) {
88
+ // Remove one borrow from the receiver if appropriate to positively verify that
89
+ // the receiver `&self` type and the return type are the same, depending on the
90
+ // involved trait being checked.
91
+ ty:: Ref ( _, ty, _) if * peel_ref => ty,
92
+ // When it comes to `Clone` we need to check the `receiver_ty` directly.
93
+ // FIXME: we must come up with a better strategy for this.
94
+ _ => receiver_ty,
95
+ } ;
96
+ let expr_ty = cx. typeck_results ( ) . expr_ty_adjusted ( expr) ;
97
+ if receiver_ty != expr_ty {
98
+ // This lint will only trigger if the receiver type and resulting expression \
99
+ // type are the same, implying that the method call is unnecessary.
100
+ return ;
101
+ }
102
+ let expr_span = expr. span ;
103
+ let note = format ! (
104
+ "the type `{:?}` which `{}` is being called on is the same as \
105
+ the type returned from `{}`, so the method call does not do \
106
+ anything and can be removed",
107
+ receiver_ty, method, method,
108
+ ) ;
109
+
110
+ let span = expr_span. with_lo ( receiver. span . hi ( ) ) ;
111
+ cx. struct_span_lint ( NOOP_METHOD_CALL , span, |lint| {
112
+ let method = & call. ident . name ;
113
+ let message = format ! (
114
+ "call to `.{}()` on a reference in this situation does nothing" ,
115
+ & method,
116
+ ) ;
117
+ lint. build ( & message)
118
+ . span_label ( span, "unnecessary method call" )
119
+ . note ( & note)
120
+ . emit ( )
121
+ } ) ;
108
122
}
109
123
}
110
124
}
0 commit comments