1
1
use clippy_utils:: diagnostics:: { span_lint_hir, span_lint_hir_and_then} ;
2
+ use clippy_utils:: mir:: { visit_local_usage, LocalUsage } ;
2
3
use clippy_utils:: source:: snippet_opt;
3
4
use clippy_utils:: ty:: { has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth} ;
4
5
use clippy_utils:: { fn_has_unsatisfiable_preds, match_def_path, paths} ;
@@ -7,10 +8,7 @@ use rustc_errors::Applicability;
7
8
use rustc_hir:: intravisit:: FnKind ;
8
9
use rustc_hir:: { def_id, Body , FnDecl , HirId } ;
9
10
use rustc_lint:: { LateContext , LateLintPass } ;
10
- use rustc_middle:: mir:: {
11
- self , traversal,
12
- visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor as _} ,
13
- } ;
11
+ use rustc_middle:: mir:: { self , visit:: Visitor as _} ;
14
12
use rustc_middle:: ty:: { self , Ty } ;
15
13
use rustc_mir_dataflow:: Analysis ;
16
14
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
@@ -381,86 +379,42 @@ struct CloneUsage {
381
379
/// Whether the clone value is mutated.
382
380
clone_consumed_or_mutated : bool ,
383
381
}
384
- fn visit_clone_usage ( cloned : mir:: Local , clone : mir:: Local , mir : & mir:: Body < ' _ > , bb : mir:: BasicBlock ) -> CloneUsage {
385
- struct V {
386
- cloned : mir:: Local ,
387
- clone : mir:: Local ,
388
- result : CloneUsage ,
389
- }
390
- impl < ' tcx > mir:: visit:: Visitor < ' tcx > for V {
391
- fn visit_basic_block_data ( & mut self , block : mir:: BasicBlock , data : & mir:: BasicBlockData < ' tcx > ) {
392
- let statements = & data. statements ;
393
- for ( statement_index, statement) in statements. iter ( ) . enumerate ( ) {
394
- self . visit_statement ( statement, mir:: Location { block, statement_index } ) ;
395
- }
396
382
397
- self . visit_terminator (
398
- data. terminator ( ) ,
399
- mir:: Location {
400
- block,
401
- statement_index : statements. len ( ) ,
402
- } ,
403
- ) ;
383
+ fn visit_clone_usage ( cloned : mir:: Local , clone : mir:: Local , mir : & mir:: Body < ' _ > , bb : mir:: BasicBlock ) -> CloneUsage {
384
+ if let Some (
385
+ & [
386
+ LocalUsage {
387
+ local_use_loc : cloned_use_loc,
388
+ local_consume_or_mutate_loc : cloned_consume_or_mutate_loc,
389
+ } ,
390
+ LocalUsage {
391
+ local_use_loc : _,
392
+ local_consume_or_mutate_loc : clone_consume_or_mutate_loc,
393
+ } ,
394
+ ] ,
395
+ ) = visit_local_usage (
396
+ & [ cloned, clone] ,
397
+ mir,
398
+ mir:: Location {
399
+ block : bb,
400
+ statement_index : mir. basic_blocks [ bb] . statements . len ( ) ,
401
+ } ,
402
+ )
403
+ . as_deref ( )
404
+ {
405
+ CloneUsage {
406
+ cloned_used : cloned_use_loc. is_some ( ) ,
407
+ cloned_consume_or_mutate_loc,
408
+ // Consider non-temporary clones consumed.
409
+ // TODO: Actually check for mutation of non-temporaries.
410
+ clone_consumed_or_mutated : mir. local_kind ( clone) != mir:: LocalKind :: Temp
411
+ || clone_consume_or_mutate_loc. is_some ( ) ,
404
412
}
405
-
406
- fn visit_place ( & mut self , place : & mir:: Place < ' tcx > , ctx : PlaceContext , loc : mir:: Location ) {
407
- let local = place. local ;
408
-
409
- if local == self . cloned
410
- && !matches ! (
411
- ctx,
412
- PlaceContext :: MutatingUse ( MutatingUseContext :: Drop ) | PlaceContext :: NonUse ( _)
413
- )
414
- {
415
- self . result . cloned_used = true ;
416
- self . result . cloned_consume_or_mutate_loc = self . result . cloned_consume_or_mutate_loc . or_else ( || {
417
- matches ! (
418
- ctx,
419
- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Move )
420
- | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow )
421
- )
422
- . then ( || loc)
423
- } ) ;
424
- } else if local == self . clone {
425
- match ctx {
426
- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Move )
427
- | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow ) => {
428
- self . result . clone_consumed_or_mutated = true ;
429
- } ,
430
- _ => { } ,
431
- }
432
- }
413
+ } else {
414
+ CloneUsage {
415
+ cloned_used : true ,
416
+ cloned_consume_or_mutate_loc : None ,
417
+ clone_consumed_or_mutated : true ,
433
418
}
434
419
}
435
-
436
- let init = CloneUsage {
437
- cloned_used : false ,
438
- cloned_consume_or_mutate_loc : None ,
439
- // Consider non-temporary clones consumed.
440
- // TODO: Actually check for mutation of non-temporaries.
441
- clone_consumed_or_mutated : mir. local_kind ( clone) != mir:: LocalKind :: Temp ,
442
- } ;
443
- traversal:: ReversePostorder :: new ( mir, bb)
444
- . skip ( 1 )
445
- . fold ( init, |usage, ( tbb, tdata) | {
446
- // Short-circuit
447
- if ( usage. cloned_used && usage. clone_consumed_or_mutated ) ||
448
- // Give up on loops
449
- tdata. terminator ( ) . successors ( ) . any ( |s| s == bb)
450
- {
451
- return CloneUsage {
452
- cloned_used : true ,
453
- clone_consumed_or_mutated : true ,
454
- ..usage
455
- } ;
456
- }
457
-
458
- let mut v = V {
459
- cloned,
460
- clone,
461
- result : usage,
462
- } ;
463
- v. visit_basic_block_data ( tbb, tdata) ;
464
- v. result
465
- } )
466
420
}
0 commit comments