8
8
// except according to those terms.
9
9
10
10
use crate :: rustc:: hir:: intravisit:: { walk_expr, NestedVisitorMap , Visitor } ;
11
- use crate :: rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
11
+ use crate :: rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass , Lint } ;
12
12
use crate :: rustc:: { declare_tool_lint, lint_array} ;
13
13
use crate :: rustc:: hir:: * ;
14
14
use if_chain:: if_chain;
15
15
use crate :: syntax_pos:: symbol:: Symbol ;
16
16
use crate :: syntax:: ast:: { LitKind , NodeId } ;
17
- use crate :: syntax:: source_map:: Span ;
18
- use crate :: utils:: { match_qpath, span_lint_and_then, SpanlessEq } ;
19
- use crate :: utils:: get_enclosing_block;
17
+ use crate :: utils:: { match_qpath, span_lint_and_then, SpanlessEq , get_enclosing_block} ;
18
+ use crate :: utils:: sugg:: Sugg ;
20
19
use crate :: rustc_errors:: { Applicability } ;
21
20
22
21
/// **What it does:** Checks slow zero-filled vector initialization
@@ -70,15 +69,15 @@ impl LintPass for Pass {
70
69
}
71
70
}
72
71
73
- /// VecInitialization contains data regarding a vector initialized with `with_capacity` and then
72
+ /// `VecAllocation` contains data regarding a vector allocated with `with_capacity` and then
74
73
/// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or
75
74
/// `vec = Vec::with_capacity(0)`
76
- struct VecInitialization < ' tcx > {
75
+ struct VecAllocation < ' tcx > {
77
76
/// Symbol of the local variable name
78
77
variable_name : Symbol ,
79
78
80
- /// Reference to the expression which initializes the vector
81
- initialization_expr : & ' tcx Expr ,
79
+ /// Reference to the expression which allocates the vector
80
+ allocation_expr : & ' tcx Expr ,
82
81
83
82
/// Reference to the expression used as argument on `with_capacity` call. This is used
84
83
/// to only match slow zero-filling idioms of the same length than vector initialization.
@@ -111,13 +110,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
111
110
if let Some ( ref len_arg) = Pass :: is_vec_with_capacity( right) ;
112
111
113
112
then {
114
- let vi = VecInitialization {
113
+ let vi = VecAllocation {
115
114
variable_name: variable_name. ident. name,
116
- initialization_expr : right,
115
+ allocation_expr : right,
117
116
len_expr: len_arg,
118
117
} ;
119
118
120
- Pass :: search_slow_initialization ( cx, vi, expr. id) ;
119
+ Pass :: search_initialization ( cx, vi, expr. id) ;
121
120
}
122
121
}
123
122
}
@@ -132,13 +131,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
132
131
if let Some ( ref len_arg) = Pass :: is_vec_with_capacity( init) ;
133
132
134
133
then {
135
- let vi = VecInitialization {
134
+ let vi = VecAllocation {
136
135
variable_name: variable_name. name,
137
- initialization_expr : init,
136
+ allocation_expr : init,
138
137
len_expr: len_arg,
139
138
} ;
140
139
141
- Pass :: search_slow_initialization ( cx, vi, stmt. node. id( ) ) ;
140
+ Pass :: search_initialization ( cx, vi, stmt. node. id( ) ) ;
142
141
}
143
142
}
144
143
}
@@ -162,10 +161,10 @@ impl Pass {
162
161
None
163
162
}
164
163
165
- /// Search a slow initialization for the given vector
166
- fn search_slow_initialization < ' tcx > (
164
+ /// Search initialization for the given vector
165
+ fn search_initialization < ' tcx > (
167
166
cx : & LateContext < ' _ , ' tcx > ,
168
- vec_initialization : VecInitialization < ' tcx > ,
167
+ vec_alloc : VecAllocation < ' tcx > ,
169
168
parent_node : NodeId
170
169
) {
171
170
let enclosing_body = get_enclosing_block ( cx, parent_node) ;
@@ -174,72 +173,76 @@ impl Pass {
174
173
return ;
175
174
}
176
175
177
- let mut v = SlowInitializationVisitor {
176
+ let mut v = VectorInitializationVisitor {
178
177
cx,
179
- vec_ini : vec_initialization ,
178
+ vec_alloc ,
180
179
slow_expression : None ,
181
180
initialization_found : false ,
182
181
} ;
183
182
184
183
v. visit_block ( enclosing_body. unwrap ( ) ) ;
185
184
186
- if let Some ( ref initialization_expr) = v. slow_expression {
187
- let alloc_span = v. vec_ini . initialization_expr . span ;
188
- Pass :: lint_initialization ( cx, initialization_expr, alloc_span) ;
185
+ if let Some ( ref allocation_expr) = v. slow_expression {
186
+ Pass :: lint_initialization ( cx, allocation_expr, & v. vec_alloc ) ;
189
187
}
190
188
}
191
189
192
- fn lint_initialization < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , initialization : & InitializationType < ' tcx > , alloc_span : Span ) {
190
+ fn lint_initialization < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , initialization : & InitializationType < ' tcx > , vec_alloc : & VecAllocation < ' _ > ) {
193
191
match initialization {
194
192
InitializationType :: UnsafeSetLen ( e) =>
195
- Pass :: lint_unsafe_initialization ( cx, e, alloc_span) ,
193
+ Pass :: emit_lint (
194
+ cx,
195
+ e,
196
+ vec_alloc,
197
+ "unsafe vector initialization" ,
198
+ UNSAFE_VECTOR_INITIALIZATION
199
+ ) ,
196
200
197
201
InitializationType :: Extend ( e) |
198
202
InitializationType :: Resize ( e) =>
199
- Pass :: lint_slow_initialization ( cx, e, alloc_span) ,
203
+ Pass :: emit_lint (
204
+ cx,
205
+ e,
206
+ vec_alloc,
207
+ "slow zero-filling initialization" ,
208
+ SLOW_VECTOR_INITIALIZATION
209
+ )
200
210
} ;
201
211
}
202
212
203
- fn lint_slow_initialization < ' tcx > (
213
+ fn emit_lint < ' tcx > (
204
214
cx : & LateContext < ' _ , ' tcx > ,
205
215
slow_fill : & Expr ,
206
- alloc_span : Span ,
216
+ vec_alloc : & VecAllocation < ' _ > ,
217
+ msg : & str ,
218
+ lint : & ' static Lint
207
219
) {
208
- span_lint_and_then (
209
- cx,
210
- SLOW_VECTOR_INITIALIZATION ,
211
- slow_fill. span ,
212
- "detected slow zero-filling initialization" ,
213
- |db| {
214
- db. span_suggestion_with_applicability ( alloc_span, "consider replacing with" , "vec![0; ..]" . to_string ( ) , Applicability :: Unspecified ) ;
215
- }
216
- ) ;
217
- }
220
+ let len_expr = Sugg :: hir ( cx, vec_alloc. len_expr , "len" ) ;
218
221
219
- fn lint_unsafe_initialization < ' tcx > (
220
- cx : & LateContext < ' _ , ' tcx > ,
221
- slow_fill : & Expr ,
222
- alloc_span : Span ,
223
- ) {
224
222
span_lint_and_then (
225
223
cx,
226
- UNSAFE_VECTOR_INITIALIZATION ,
224
+ lint ,
227
225
slow_fill. span ,
228
- "detected unsafe vector initialization" ,
226
+ msg ,
229
227
|db| {
230
- db. span_suggestion_with_applicability ( alloc_span, "consider replacing with" , "vec![0; ..]" . to_string ( ) , Applicability :: Unspecified ) ;
228
+ db. span_suggestion_with_applicability (
229
+ vec_alloc. allocation_expr . span ,
230
+ "consider replace allocation with" ,
231
+ format ! ( "vec![0; {}]" , len_expr) ,
232
+ Applicability :: Unspecified
233
+ ) ;
231
234
}
232
235
) ;
233
236
}
234
237
}
235
238
236
- /// SlowInitializationVisitor searches for slow zero filling vector initialization, for the given
239
+ /// `VectorInitializationVisitor` searches for unsafe or slow vector initializations for the given
237
240
/// vector.
238
- struct SlowInitializationVisitor < ' a , ' tcx : ' a > {
241
+ struct VectorInitializationVisitor < ' a , ' tcx : ' a > {
239
242
cx : & ' a LateContext < ' a , ' tcx > ,
240
243
241
244
/// Contains the information
242
- vec_ini : VecInitialization < ' tcx > ,
245
+ vec_alloc : VecAllocation < ' tcx > ,
243
246
244
247
/// Contains, if found, the slow initialization expression
245
248
slow_expression : Option < InitializationType < ' tcx > > ,
@@ -248,14 +251,14 @@ struct SlowInitializationVisitor<'a, 'tcx: 'a> {
248
251
initialization_found : bool ,
249
252
}
250
253
251
- impl < ' a , ' tcx > SlowInitializationVisitor < ' a , ' tcx > {
254
+ impl < ' a , ' tcx > VectorInitializationVisitor < ' a , ' tcx > {
252
255
/// Checks if the given expression is extending a vector with `repeat(0).take(..)`
253
256
fn search_slow_extend_filling ( & mut self , expr : & ' tcx Expr ) {
254
257
if_chain ! {
255
258
if self . initialization_found;
256
259
if let ExprKind :: MethodCall ( ref path, _, ref args) = expr. node;
257
260
if let ExprKind :: Path ( ref qpath_subj) = args[ 0 ] . node;
258
- if match_qpath( & qpath_subj, & [ & self . vec_ini . variable_name. to_string( ) ] ) ;
261
+ if match_qpath( & qpath_subj, & [ & self . vec_alloc . variable_name. to_string( ) ] ) ;
259
262
if path. ident. name == "extend" ;
260
263
if let Some ( ref extend_arg) = args. get( 1 ) ;
261
264
if self . is_repeat_take( extend_arg) ;
@@ -272,7 +275,7 @@ impl<'a, 'tcx> SlowInitializationVisitor<'a, 'tcx> {
272
275
if self . initialization_found;
273
276
if let ExprKind :: MethodCall ( ref path, _, ref args) = expr. node;
274
277
if let ExprKind :: Path ( ref qpath_subj) = args[ 0 ] . node;
275
- if match_qpath( & qpath_subj, & [ & self . vec_ini . variable_name. to_string( ) ] ) ;
278
+ if match_qpath( & qpath_subj, & [ & self . vec_alloc . variable_name. to_string( ) ] ) ;
276
279
if path. ident. name == "resize" ;
277
280
if let ( Some ( ref len_arg) , Some ( fill_arg) ) = ( args. get( 1 ) , args. get( 2 ) ) ;
278
281
@@ -281,7 +284,7 @@ impl<'a, 'tcx> SlowInitializationVisitor<'a, 'tcx> {
281
284
if let LitKind :: Int ( 0 , _) = lit. node;
282
285
283
286
// Check that len expression is equals to `with_capacity` expression
284
- if SpanlessEq :: new( self . cx) . eq_expr( len_arg, self . vec_ini . len_expr) ;
287
+ if SpanlessEq :: new( self . cx) . eq_expr( len_arg, self . vec_alloc . len_expr) ;
285
288
286
289
then {
287
290
self . slow_expression = Some ( InitializationType :: Resize ( expr) ) ;
@@ -295,12 +298,12 @@ impl<'a, 'tcx> SlowInitializationVisitor<'a, 'tcx> {
295
298
if self . initialization_found;
296
299
if let ExprKind :: MethodCall ( ref path, _, ref args) = expr. node;
297
300
if let ExprKind :: Path ( ref qpath_subj) = args[ 0 ] . node;
298
- if match_qpath( & qpath_subj, & [ & self . vec_ini . variable_name. to_string( ) ] ) ;
301
+ if match_qpath( & qpath_subj, & [ & self . vec_alloc . variable_name. to_string( ) ] ) ;
299
302
if path. ident. name == "set_len" ;
300
303
if let Some ( ref len_arg) = args. get( 1 ) ;
301
304
302
305
// Check that len expression is equals to `with_capacity` expression
303
- if SpanlessEq :: new( self . cx) . eq_expr( len_arg, self . vec_ini . len_expr) ;
306
+ if SpanlessEq :: new( self . cx) . eq_expr( len_arg, self . vec_alloc . len_expr) ;
304
307
305
308
then {
306
309
self . slow_expression = Some ( InitializationType :: UnsafeSetLen ( expr) ) ;
@@ -320,7 +323,7 @@ impl<'a, 'tcx> SlowInitializationVisitor<'a, 'tcx> {
320
323
321
324
// Check that len expression is equals to `with_capacity` expression
322
325
if let Some ( ref len_arg) = take_args. get( 1 ) ;
323
- if SpanlessEq :: new( self . cx) . eq_expr( len_arg, self . vec_ini . len_expr) ;
326
+ if SpanlessEq :: new( self . cx) . eq_expr( len_arg, self . vec_alloc . len_expr) ;
324
327
325
328
then {
326
329
return true ;
@@ -349,15 +352,15 @@ impl<'a, 'tcx> SlowInitializationVisitor<'a, 'tcx> {
349
352
}
350
353
}
351
354
352
- impl < ' a , ' tcx > Visitor < ' tcx > for SlowInitializationVisitor < ' a , ' tcx > {
355
+ impl < ' a , ' tcx > Visitor < ' tcx > for VectorInitializationVisitor < ' a , ' tcx > {
353
356
fn visit_expr ( & mut self , expr : & ' tcx Expr ) {
354
357
// Stop the search if we already found a slow zero-filling initialization
355
358
if self . slow_expression . is_some ( ) {
356
359
return
357
360
}
358
361
359
362
// Skip all the expressions previous to the vector initialization
360
- if self . vec_ini . initialization_expr . id == expr. id {
363
+ if self . vec_alloc . allocation_expr . id == expr. id {
361
364
self . initialization_found = true ;
362
365
}
363
366
0 commit comments