+ let end_linable = block.expr.map_or_else(
+ || end_eq != 0,
+ |expr| {
+ intravisit::walk_expr(&mut end_walker, expr);
+ end_walker.uses.iter().any(|x| !block_defs.contains(x))
+ },
+ );
+
+ if end_linable {
+ end_walker.def_symbols.drain().for_each(|x| {
+ moved_syms.insert(x);
+ });
+ }
+
+ emit_branches_sharing_code_lint(
+ cx,
+ start_eq,
+ end_eq,
+ end_linable,
+ check_for_warn_of_moved_symbol(cx, &moved_syms, expr),
+ blocks,
+ expr,
+ );
+ }
+}
+
+struct BlockEqual {
+ /// The amount statements that are equal from the start
+ start_eq: usize,
+ /// The amount statements that are equal from the end
+ end_eq: usize,
+ /// An indication if the block expressions are the same. This will also be true if both are
+ /// `None`
+ expr_eq: bool,
+}
+
+/// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
+/// abort any further processing and avoid duplicate lint triggers.
+fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<BlockEqual> {
+ let mut start_eq = usize::MAX;
+ let mut end_eq = usize::MAX;
+ let mut expr_eq = true;
+ for win in blocks.windows(2) {
+ let l_stmts = win[0].stmts;
+ let r_stmts = win[1].stmts;
+
+ // `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
+ // The comparison therefore needs to be done in a way that builds the correct context.
+ let mut evaluator = SpanlessEq::new(cx);
+ let mut evaluator = evaluator.inter_expr();
+
+ let current_start_eq = count_eq(&mut l_stmts.iter(), &mut r_stmts.iter(), |l, r| evaluator.eq_stmt(l, r));
+
+ let current_end_eq = {
+ // We skip the middle statements which can't be equal
+ let end_comparison_count = l_stmts.len().min(r_stmts.len()) - current_start_eq;
+ let it1 = l_stmts.iter().skip(l_stmts.len() - end_comparison_count);
+ let it2 = r_stmts.iter().skip(r_stmts.len() - end_comparison_count);
+ it1.zip(it2)
+ .fold(0, |acc, (l, r)| if evaluator.eq_stmt(l, r) { acc + 1 } else { 0 })