@@ -425,7 +425,9 @@ fn scan_block_for_eq<'tcx>(
425
425
modifies_any_local ( cx, stmt, & cond_locals)
426
426
|| !eq_stmts ( stmt, blocks, |b| b. stmts . get ( i) , & mut eq, & mut moved_locals)
427
427
} )
428
- . map_or ( block. stmts . len ( ) , |( i, _) | i) ;
428
+ . map_or ( block. stmts . len ( ) , |( i, stmt) | {
429
+ adjust_by_closest_callsite ( i, stmt, block. stmts [ ..i] . iter ( ) . enumerate ( ) . rev ( ) )
430
+ } ) ;
429
431
430
432
if local_needs_ordered_drop {
431
433
return BlockEq {
@@ -467,7 +469,9 @@ fn scan_block_for_eq<'tcx>(
467
469
. is_none_or ( |s| hash != hash_stmt ( cx, s) )
468
470
} )
469
471
} )
470
- . map_or ( block. stmts . len ( ) - start_end_eq, |( i, _) | i) ;
472
+ . map_or ( block. stmts . len ( ) - start_end_eq, |( i, stmt) | {
473
+ adjust_by_closest_callsite ( i, stmt, ( 0 ..i) . rev ( ) . zip ( block. stmts [ ( block. stmts . len ( ) - i) ..] . iter ( ) ) )
474
+ } ) ;
471
475
472
476
let moved_locals_at_start = moved_locals. len ( ) ;
473
477
let mut i = end_search_start;
@@ -522,6 +526,49 @@ fn scan_block_for_eq<'tcx>(
522
526
}
523
527
}
524
528
529
+ /// Adjusts the index for which the statements begin to differ to the closest macro callsite. This
530
+ /// avoids giving suggestions that requires splitting a macro call in half, when only a part of the
531
+ /// macro expansion is equal.
532
+ ///
533
+ /// For example, for the following macro:
534
+ /// ```rust,ignore
535
+ /// macro_rules! foo {
536
+ /// ($x:expr) => {
537
+ /// let y = 42;
538
+ /// $x;
539
+ /// };
540
+ /// }
541
+ /// ```
542
+ /// If the macro is called like this:
543
+ /// ```rust,ignore
544
+ /// if false {
545
+ /// let z = 42;
546
+ /// foo!(println!("Hello"));
547
+ /// } else {
548
+ /// let z = 42;
549
+ /// foo!(println!("World"));
550
+ /// }
551
+ /// ```
552
+ /// Although the expanded `let y = 42;` is equal, the macro call should not be included in the
553
+ /// suggestion.
554
+ fn adjust_by_closest_callsite < ' tcx > (
555
+ i : usize ,
556
+ stmt : & ' tcx Stmt < ' tcx > ,
557
+ mut iter : impl Iterator < Item = ( usize , & ' tcx Stmt < ' tcx > ) > ,
558
+ ) -> usize {
559
+ let Some ( ( _, first) ) = iter. next ( ) else {
560
+ return 0 ;
561
+ } ;
562
+
563
+ // If it is already at the boundary of a macro call, then just return.
564
+ if first. span . source_callsite ( ) != stmt. span . source_callsite ( ) {
565
+ return i;
566
+ }
567
+
568
+ iter. find ( |( _, stmt) | stmt. span . source_callsite ( ) != first. span . source_callsite ( ) )
569
+ . map_or ( 0 , |( i, _) | i + 1 )
570
+ }
571
+
525
572
fn check_for_warn_of_moved_symbol ( cx : & LateContext < ' _ > , symbols : & [ ( HirId , Symbol ) ] , if_expr : & Expr < ' _ > ) -> bool {
526
573
get_enclosing_block ( cx, if_expr. hir_id ) . is_some_and ( |block| {
527
574
let ignore_span = block. span . shrink_to_lo ( ) . to ( if_expr. span ) ;
0 commit comments