11use clippy_utils:: diagnostics:: { span_lint_and_note, span_lint_and_then} ;
22use clippy_utils:: source:: { first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt} ;
33use clippy_utils:: {
4- both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, in_macro, parent_node_is_if_expr ,
4+ both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, in_macro, is_else_clause ,
55 run_lints, search_same, ContainsName , SpanlessEq , SpanlessHash ,
66} ;
77use if_chain:: if_chain;
@@ -188,13 +188,18 @@ fn lint_same_then_else<'tcx>(
188188 expr : & ' tcx Expr < ' _ > ,
189189) {
190190 // We only lint ifs with multiple blocks
191- if blocks. len ( ) < 2 || parent_node_is_if_expr ( expr , cx ) {
191+ if blocks. len ( ) < 2 || is_else_clause ( cx . tcx , expr ) {
192192 return ;
193193 }
194194
195195 // Check if each block has shared code
196196 let has_expr = blocks[ 0 ] . expr . is_some ( ) ;
197- let ( start_eq, mut end_eq, expr_eq) = scan_block_for_eq ( cx, blocks) ;
197+
198+ let ( start_eq, mut end_eq, expr_eq) = if let Some ( block_eq) = scan_block_for_eq ( cx, blocks) {
199+ ( block_eq. start_eq , block_eq. end_eq , block_eq. expr_eq )
200+ } else {
201+ return ;
202+ } ;
198203
199204 // BRANCHES_SHARING_CODE prerequisites
200205 if has_conditional_else || ( start_eq == 0 && end_eq == 0 && ( has_expr && !expr_eq) ) {
@@ -290,15 +295,19 @@ fn lint_same_then_else<'tcx>(
290295 }
291296}
292297
293- /// The return tuple is structured as follows:
294- /// 1. The amount of equal statements from the start
295- /// 2. The amount of equal statements from the end
296- /// 3. An indication if the block expressions are the same. This will also be true if both are
297- /// `None`
298- ///
299- /// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `(0, 0,
300- /// false)` to aboard any further processing and avoid duplicate lint triggers.
301- fn scan_block_for_eq ( cx : & LateContext < ' tcx > , blocks : & [ & Block < ' tcx > ] ) -> ( usize , usize , bool ) {
298+ struct BlockEqual {
299+ /// The amount statements that are equal from the start
300+ start_eq : usize ,
301+ /// The amount statements that are equal from the end
302+ end_eq : usize ,
303+ /// An indication if the block expressions are the same. This will also be true if both are
304+ /// `None`
305+ expr_eq : bool ,
306+ }
307+
308+ /// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
309+ /// abort any further processing and avoid duplicate lint triggers.
310+ fn scan_block_for_eq ( cx : & LateContext < ' tcx > , blocks : & [ & Block < ' tcx > ] ) -> Option < BlockEqual > {
302311 let mut start_eq = usize:: MAX ;
303312 let mut end_eq = usize:: MAX ;
304313 let mut expr_eq = true ;
@@ -308,7 +317,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize,
308317
309318 // `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
310319 // The comparison therefore needs to be done in a way that builds the correct context.
311- let mut evaluator = SpanlessEq :: new ( cx) . enable_check_inferred_local_types ( ) ;
320+ let mut evaluator = SpanlessEq :: new ( cx) ;
312321 let mut evaluator = evaluator. inter_expr ( ) ;
313322
314323 let current_start_eq = count_eq ( & mut l_stmts. iter ( ) , & mut r_stmts. iter ( ) , |l, r| evaluator. eq_stmt ( l, r) ) ;
@@ -340,7 +349,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize,
340349 "same as this" ,
341350 ) ;
342351
343- return ( 0 , 0 , false ) ;
352+ return None ;
344353 }
345354 }
346355
@@ -360,7 +369,11 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> (usize,
360369 end_eq = min_block_size - start_eq;
361370 }
362371
363- ( start_eq, end_eq, expr_eq)
372+ Some ( BlockEqual {
373+ start_eq,
374+ end_eq,
375+ expr_eq,
376+ } )
364377}
365378
366379fn check_for_warn_of_moved_symbol (
0 commit comments