@@ -2429,7 +2429,6 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
2429
2429
if let ExprKind :: Block ( ref block, _) = expr. kind {
2430
2430
for ref stmt in block. stmts {
2431
2431
if_chain ! {
2432
- // TODO also work for assignments to an existing variable
2433
2432
if let StmtKind :: Local (
2434
2433
Local { pat: Pat { kind: PatKind :: Binding ( _, _, ident, .. ) , .. } ,
2435
2434
init: Some ( ref init_expr) , .. }
@@ -2446,21 +2445,22 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
2446
2445
if iter_calls. len( ) == 1 ;
2447
2446
then {
2448
2447
// Suggest replacing iter_call with iter_replacement, and removing stmt
2448
+ let iter_call = & iter_calls[ 0 ] ;
2449
2449
span_lint_and_then(
2450
2450
cx,
2451
2451
NEEDLESS_COLLECT ,
2452
- stmt. span,
2452
+ stmt. span. until ( iter_call . span ) ,
2453
2453
NEEDLESS_COLLECT_MSG ,
2454
2454
|diag| {
2455
- let iter_replacement = Sugg :: hir( cx, iter_source, ".." ) . to_string ( ) ;
2455
+ let iter_replacement = format! ( "{}{}" , Sugg :: hir( cx, iter_source, ".." ) , iter_call . get_iter_method ( cx ) ) ;
2456
2456
diag. multipart_suggestion(
2457
- "Use the original Iterator instead of collecting it and then producing a new one" ,
2457
+ iter_call . get_suggestion_text ( ) ,
2458
2458
vec![
2459
2459
( stmt. span, String :: new( ) ) ,
2460
- ( iter_calls [ 0 ] . span, iter_replacement)
2460
+ ( iter_call . span, iter_replacement)
2461
2461
] ,
2462
- Applicability :: MaybeIncorrect ,
2463
- ) ;
2462
+ Applicability :: MachineApplicable , // MaybeIncorrect,
2463
+ ) . emit ( ) ;
2464
2464
} ,
2465
2465
) ;
2466
2466
}
@@ -2469,32 +2469,62 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
2469
2469
}
2470
2470
}
2471
2471
2472
- struct IntoIterVisitor < ' tcx > {
2473
- iters : Vec < & ' tcx Expr < ' tcx > > ,
2472
+ struct IterFunction {
2473
+ func : IterFunctionKind ,
2474
+ span : Span ,
2475
+ }
2476
+ impl IterFunction {
2477
+ fn get_iter_method ( & self , cx : & LateContext < ' _ > ) -> String {
2478
+ match & self . func {
2479
+ IterFunctionKind :: IntoIter => String :: new ( ) ,
2480
+ IterFunctionKind :: Len => String :: from ( ".count()" ) ,
2481
+ IterFunctionKind :: IsEmpty => String :: from ( ".next().is_none()" ) ,
2482
+ IterFunctionKind :: Contains ( span) => format ! ( ".any(|x| x == {})" , snippet( cx, * span, ".." ) ) ,
2483
+ }
2484
+ }
2485
+ fn get_suggestion_text ( & self ) -> & ' static str {
2486
+ match & self . func {
2487
+ IterFunctionKind :: IntoIter => "Use the original Iterator instead of collecting it and then producing a new one" ,
2488
+ IterFunctionKind :: Len => "Take the original Iterator's count instead of collecting it and finding the length" ,
2489
+ IterFunctionKind :: IsEmpty => "Check if the original Iterator has anything instead of collecting it and seeing if it's empty" ,
2490
+ IterFunctionKind :: Contains ( _) => "Check if the original Iterator contains an element instead of collecting then checking" ,
2491
+ }
2492
+ }
2493
+ }
2494
+ enum IterFunctionKind {
2495
+ IntoIter ,
2496
+ Len ,
2497
+ IsEmpty ,
2498
+ Contains ( Span ) ,
2499
+ }
2500
+
2501
+ struct IterFunctionVisitor {
2502
+ uses : Vec < IterFunction > ,
2474
2503
seen_other : bool ,
2475
2504
target : String ,
2476
2505
}
2477
- impl < ' tcx > Visitor < ' tcx > for IntoIterVisitor < ' tcx > {
2506
+ impl < ' tcx > Visitor < ' tcx > for IterFunctionVisitor {
2478
2507
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
2479
- match & expr. kind {
2480
- ExprKind :: MethodCall (
2481
- method_name,
2482
- _,
2483
- & [ Expr {
2484
- kind : ExprKind :: Path ( QPath :: Resolved ( _, ref path) ) ,
2485
- ..
2486
- } ] ,
2487
- _,
2488
- ) if match_path ( path, & [ & self . target ] ) => {
2489
- // TODO Check what method is being called, if it's called on target, and act
2490
- // accordingly
2491
- if method_name. ident . name == sym ! ( into_iter) {
2492
- self . iters . push ( expr) ;
2493
- } else {
2494
- self . seen_other = true ;
2508
+ if_chain ! {
2509
+ if let ExprKind :: MethodCall ( method_name, _, ref args, _) = & expr. kind;
2510
+ if let Some ( Expr { kind: ExprKind :: Path ( QPath :: Resolved ( _, ref path) ) , .. } ) = args. get( 0 ) ;
2511
+ if match_path( path, & [ & self . target] ) ;
2512
+ then {
2513
+ let into_iter = sym!( into_iter) ;
2514
+ let len = sym!( len) ;
2515
+ let is_empty = sym!( is_empty) ;
2516
+ let contains = sym!( contains) ;
2517
+ match method_name. ident. name {
2518
+ name if name == into_iter => self . uses. push( IterFunction { func: IterFunctionKind :: IntoIter , span: expr. span } ) ,
2519
+ name if name == len => self . uses. push( IterFunction { func: IterFunctionKind :: Len , span: expr. span } ) ,
2520
+ name if name == is_empty => self . uses. push( IterFunction { func: IterFunctionKind :: IsEmpty , span: expr. span } ) ,
2521
+ name if name == contains => self . uses. push( IterFunction { func: IterFunctionKind :: Contains ( args[ 1 ] . span) , span: expr. span } ) ,
2522
+ _ => self . seen_other = true ,
2495
2523
}
2496
- } ,
2497
- _ => walk_expr ( self , expr) ,
2524
+ }
2525
+ else {
2526
+ walk_expr( self , expr) ;
2527
+ }
2498
2528
}
2499
2529
}
2500
2530
@@ -2506,17 +2536,17 @@ impl<'tcx> Visitor<'tcx> for IntoIterVisitor<'tcx> {
2506
2536
2507
2537
/// Detect the occurences of calls to `iter` or `into_iter` for the
2508
2538
/// given identifier
2509
- fn detect_iter_and_into_iters < ' tcx > ( block : & ' tcx Block < ' tcx > , identifier : Ident ) -> Option < Vec < & ' tcx Expr < ' tcx > > > {
2510
- let mut visitor = IntoIterVisitor {
2511
- iters : Vec :: new ( ) ,
2539
+ fn detect_iter_and_into_iters < ' tcx > ( block : & ' tcx Block < ' tcx > , identifier : Ident ) -> Option < Vec < IterFunction > > {
2540
+ let mut visitor = IterFunctionVisitor {
2541
+ uses : Vec :: new ( ) ,
2512
2542
target : identifier. name . to_ident_string ( ) ,
2513
2543
seen_other : false ,
2514
2544
} ;
2515
2545
visitor. visit_block ( block) ;
2516
2546
if visitor. seen_other {
2517
2547
None
2518
2548
} else {
2519
- Some ( visitor. iters )
2549
+ Some ( visitor. uses )
2520
2550
}
2521
2551
}
2522
2552
0 commit comments