1
1
use rustc:: hir:: * ;
2
+ use rustc:: hir:: map:: * ;
2
3
use rustc:: hir:: intravisit:: FnKind ;
3
4
use rustc:: lint:: * ;
4
5
use rustc:: ty:: { self , RegionKind , TypeFoldable } ;
@@ -22,13 +23,20 @@ use std::borrow::Cow;
22
23
/// sometimes avoid
23
24
/// unnecessary allocations.
24
25
///
25
- /// **Known problems:** Hopefully none.
26
+ /// **Known problems:**
27
+ /// * This lint suggests taking an argument by reference,
28
+ /// however sometimes it is better to let users decide the argument type
29
+ /// (by using `Borrow` trait, for example), depending on how the function is used.
26
30
///
27
31
/// **Example:**
28
32
/// ```rust
29
33
/// fn foo(v: Vec<i32>) {
30
34
/// assert_eq!(v.len(), 42);
31
35
/// }
36
+ /// // should be
37
+ /// fn foo(v: &[i32]) {
38
+ /// assert_eq!(v.len(), 42);
39
+ /// }
32
40
/// ```
33
41
declare_lint ! {
34
42
pub NEEDLESS_PASS_BY_VALUE ,
@@ -73,9 +81,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
73
81
}
74
82
}
75
83
} ,
84
+ FnKind :: Method ( ..) => ( ) ,
76
85
_ => return ,
77
86
}
78
87
88
+ // Exclude non-inherent impls
89
+ if let Some ( NodeItem ( item) ) = cx. tcx . hir . find ( cx. tcx . hir . get_parent_node ( node_id) ) {
90
+ if matches ! ( item. node, ItemImpl ( _, _, _, _, Some ( _) , _, _) | ItemDefaultImpl ( ..) ) {
91
+ return ;
92
+ }
93
+ }
94
+
79
95
// Allow `Borrow` or functions to be taken by value
80
96
let borrow_trait = need ! ( get_trait_def_id( cx, & paths:: BORROW_TRAIT ) ) ;
81
97
let fn_traits = [
@@ -109,7 +125,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
109
125
} = {
110
126
let mut ctx = MovedVariablesCtxt :: new ( cx) ;
111
127
let region_scope_tree = & cx. tcx . region_scope_tree ( fn_def_id) ;
112
- euv:: ExprUseVisitor :: new ( & mut ctx, cx. tcx , cx. param_env , region_scope_tree, cx. tables , None ) . consume_body ( body) ;
128
+ euv:: ExprUseVisitor :: new ( & mut ctx, cx. tcx , cx. param_env , region_scope_tree, cx. tables , None )
129
+ . consume_body ( body) ;
113
130
ctx
114
131
} ;
115
132
@@ -127,6 +144,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
127
144
return ;
128
145
}
129
146
147
+ // Ignore `self`s.
148
+ if idx == 0 {
149
+ if let PatKind :: Binding ( _, _, name, ..) = arg. pat . node {
150
+ if name. node . as_str ( ) == "self" {
151
+ continue ;
152
+ }
153
+ }
154
+ }
155
+
130
156
// * Exclude a type that is specifically bounded by `Borrow`.
131
157
// * Exclude a type whose reference also fulfills its bound.
132
158
// (e.g. `std::convert::AsRef`, `serde::Serialize`)
@@ -163,7 +189,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
163
189
if mode == BindingAnnotation :: Mutable || mode == BindingAnnotation :: RefMut {
164
190
continue ;
165
191
}
166
-
192
+
167
193
// Dereference suggestion
168
194
let sugg = |db: & mut DiagnosticBuilder | {
169
195
let deref_span = spans_need_deref. get( & canonical_id) ;
@@ -181,7 +207,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
181
207
db. span_suggestion( input. span,
182
208
"consider changing the type to" ,
183
209
slice_ty) ;
184
-
210
+
185
211
for ( span, suggestion) in clone_spans {
186
212
db. span_suggestion(
187
213
span,
@@ -193,18 +219,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
193
219
suggestion. into( )
194
220
) ;
195
221
}
196
-
222
+
197
223
// cannot be destructured, no need for `*` suggestion
198
224
assert!( deref_span. is_none( ) ) ;
199
225
return ;
200
226
}
201
227
}
202
-
228
+
203
229
if match_type( cx, ty, & paths:: STRING ) {
204
230
if let Some ( clone_spans) =
205
231
get_spans( cx, Some ( body. id( ) ) , idx, & [ ( "clone" , ".to_string()" ) , ( "as_str" , "" ) ] ) {
206
232
db. span_suggestion( input. span, "consider changing the type to" , "&str" . to_string( ) ) ;
207
-
233
+
208
234
for ( span, suggestion) in clone_spans {
209
235
db. span_suggestion(
210
236
span,
@@ -216,14 +242,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
216
242
suggestion. into( ) ,
217
243
) ;
218
244
}
219
-
245
+
220
246
assert!( deref_span. is_none( ) ) ;
221
247
return ;
222
248
}
223
249
}
224
-
250
+
225
251
let mut spans = vec![ ( input. span, format!( "&{}" , snippet( cx, input. span, "_" ) ) ) ] ;
226
-
252
+
227
253
// Suggests adding `*` to dereference the added reference.
228
254
if let Some ( deref_span) = deref_span {
229
255
spans. extend(
@@ -236,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
236
262
}
237
263
multispan_sugg( db, "consider taking a reference instead" . to_string( ) , spans) ;
238
264
} ;
239
-
265
+
240
266
span_lint_and_then(
241
267
cx,
242
268
NEEDLESS_PASS_BY_VALUE ,
0 commit comments