@@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
183
183
lint_same_cond ( cx, & conds) ;
184
184
lint_same_fns_in_if_cond ( cx, & conds) ;
185
185
// Block duplication
186
- lint_same_then_else ( cx, & blocks, conds. len ( ) == blocks. len ( ) , expr) ;
186
+ lint_same_then_else ( cx, & conds , & blocks, conds. len ( ) == blocks. len ( ) , expr) ;
187
187
}
188
188
}
189
189
}
@@ -192,6 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
192
192
/// Implementation of `BRANCHES_SHARING_CODE` and `IF_SAME_THEN_ELSE` if the blocks are equal.
193
193
fn lint_same_then_else < ' tcx > (
194
194
cx : & LateContext < ' tcx > ,
195
+ conds : & [ & ' tcx Expr < ' _ > ] ,
195
196
blocks : & [ & Block < ' tcx > ] ,
196
197
has_conditional_else : bool ,
197
198
expr : & ' tcx Expr < ' _ > ,
@@ -204,7 +205,7 @@ fn lint_same_then_else<'tcx>(
204
205
// Check if each block has shared code
205
206
let has_expr = blocks[ 0 ] . expr . is_some ( ) ;
206
207
207
- let ( start_eq, mut end_eq, expr_eq) = if let Some ( block_eq) = scan_block_for_eq ( cx, blocks) {
208
+ let ( start_eq, mut end_eq, expr_eq) = if let Some ( block_eq) = scan_block_for_eq ( cx, conds , blocks) {
208
209
( block_eq. start_eq , block_eq. end_eq , block_eq. expr_eq )
209
210
} else {
210
211
return ;
@@ -316,14 +317,14 @@ struct BlockEqual {
316
317
317
318
/// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
318
319
/// abort any further processing and avoid duplicate lint triggers.
319
- fn scan_block_for_eq ( cx : & LateContext < ' _ > , blocks : & [ & Block < ' _ > ] ) -> Option < BlockEqual > {
320
+ fn scan_block_for_eq ( cx : & LateContext < ' _ > , conds : & [ & Expr < ' _ > ] , blocks : & [ & Block < ' _ > ] ) -> Option < BlockEqual > {
320
321
let mut start_eq = usize:: MAX ;
321
322
let mut end_eq = usize:: MAX ;
322
323
let mut expr_eq = true ;
323
- let mut iter = blocks. windows ( 2 ) ;
324
- while let Some ( & [ win0 , win1 ] ) = iter. next ( ) {
325
- let l_stmts = win0 . stmts ;
326
- let r_stmts = win1 . stmts ;
324
+ let mut iter = blocks. windows ( 2 ) . enumerate ( ) ;
325
+ while let Some ( ( i , & [ block0 , block1 ] ) ) = iter. next ( ) {
326
+ let l_stmts = block0 . stmts ;
327
+ let r_stmts = block1 . stmts ;
327
328
328
329
// `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
329
330
// The comparison therefore needs to be done in a way that builds the correct context.
@@ -340,22 +341,26 @@ fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<Bloc
340
341
it1. zip ( it2)
341
342
. fold ( 0 , |acc, ( l, r) | if evaluator. eq_stmt ( l, r) { acc + 1 } else { 0 } )
342
343
} ;
343
- let block_expr_eq = both ( & win0 . expr , & win1 . expr , |l, r| evaluator. eq_expr ( l, r) ) ;
344
+ let block_expr_eq = both ( & block0 . expr , & block1 . expr , |l, r| evaluator. eq_expr ( l, r) ) ;
344
345
345
346
// IF_SAME_THEN_ELSE
346
347
if_chain ! {
347
348
if block_expr_eq;
348
349
if l_stmts. len( ) == r_stmts. len( ) ;
349
350
if l_stmts. len( ) == current_start_eq;
350
- if !is_lint_allowed( cx, IF_SAME_THEN_ELSE , win0. hir_id) ;
351
- if !is_lint_allowed( cx, IF_SAME_THEN_ELSE , win1. hir_id) ;
351
+ // `conds` may have one last item than `blocks`.
352
+ // Any `i` from `blocks.windows(2)` will exist in `conds`, but `i+1` may not exist on the last iteration.
353
+ if !matches!( conds[ i] . kind, ExprKind :: Let ( ..) ) ;
354
+ if !matches!( conds. get( i + 1 ) . map( |e| & e. kind) , Some ( ExprKind :: Let ( ..) ) ) ;
355
+ if !is_lint_allowed( cx, IF_SAME_THEN_ELSE , block0. hir_id) ;
356
+ if !is_lint_allowed( cx, IF_SAME_THEN_ELSE , block1. hir_id) ;
352
357
then {
353
358
span_lint_and_note(
354
359
cx,
355
360
IF_SAME_THEN_ELSE ,
356
- win0 . span,
361
+ block0 . span,
357
362
"this `if` has identical blocks" ,
358
- Some ( win1 . span) ,
363
+ Some ( block1 . span) ,
359
364
"same as this" ,
360
365
) ;
361
366
0 commit comments