about summary refs log tree commit diff
diff options
context:
space:
mode:
authorxFrednet <xFrednet@gmail.com>2021-01-16 20:37:50 +0100
committerxFrednet <xFrednet@gmail.com>2021-04-05 13:33:45 +0200
commitb1d26e544f10b814d9793294d0c05dd2ace5d0dc (patch)
tree4995c31746d8021f48c1eb431acd5eebf8de7858
parent8efc6acc05387738313798069b8553d0ab9c92e5 (diff)
downloadrust-b1d26e544f10b814d9793294d0c05dd2ace5d0dc.tar.gz
rust-b1d26e544f10b814d9793294d0c05dd2ace5d0dc.zip
Improved shared_code_in_if_blocks message and added test stderrs
-rw-r--r--clippy_lints/src/copies.rs169
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/literal_representation.rs40
-rw-r--r--tests/ui/if_same_then_else2.stderr22
-rw-r--r--tests/ui/shared_code_in_if_blocks/shared_at_bot.rs19
-rw-r--r--tests/ui/shared_code_in_if_blocks/shared_at_bot.stderr131
-rw-r--r--tests/ui/shared_code_in_if_blocks/shared_at_top.stderr83
-rw-r--r--tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs29
-rw-r--r--tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.stderr154
-rw-r--r--tests/ui/shared_code_in_if_blocks/valid_if_blocks.stderr107
10 files changed, 692 insertions, 64 deletions
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index 089f8c3ab0d..47732f4766d 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -1,16 +1,16 @@
 use crate::utils::{both, count_eq, eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash};
 use crate::utils::{
-    first_line_of_span, get_parent_expr, if_sequence, indent_of, parent_node_is_if_expr, reindent_multiline, snippet,
-    snippet_opt, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
+    first_line_of_span, get_enclosing_block, get_parent_expr, if_sequence, indent_of, parent_node_is_if_expr,
+    reindent_multiline, snippet, snippet_opt, span_lint_and_note, span_lint_and_then, ContainsName,
 };
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{source_map::Span, BytePos};
+use rustc_span::{source_map::Span, symbol::Symbol, BytePos};
 use std::borrow::Cow;
 
 declare_clippy_lint! {
@@ -184,7 +184,6 @@ fn lint_same_then_else<'tcx>(
     expr: &'tcx Expr<'_>,
 ) {
     // We only lint ifs with multiple blocks
-    // TODO xFrednet 2021-01-01: Check if it's an else if block
     if blocks.len() < 2 || parent_node_is_if_expr(expr, cx) {
         return;
     }
@@ -242,36 +241,61 @@ fn lint_same_then_else<'tcx>(
 
     // Only the start is the same
     if start_eq != 0 && end_eq == 0 && (!has_expr || !expr_eq) {
-        emit_shared_code_in_if_blocks_lint(cx, start_eq, 0, false, blocks, expr);
-    } else if end_eq != 0 && (!has_expr || !expr_eq) {
+        let block = blocks[0];
+        let start_stmts = block.stmts.split_at(start_eq).0;
+
+        let mut start_walker = UsedValueFinderVisitor::new(cx);
+        for stmt in start_stmts {
+            intravisit::walk_stmt(&mut start_walker, stmt);
+        }
+
+        emit_shared_code_in_if_blocks_lint(
+            cx,
+            start_eq,
+            0,
+            false,
+            check_for_warn_of_moved_symbol(cx, &start_walker.def_symbols, expr),
+            blocks,
+            expr,
+        );
+    } else if end_eq != 0 || (has_expr && expr_eq) {
         let block = blocks[blocks.len() - 1];
-        let stmts = block.stmts.split_at(start_eq).1;
-        let (block_stmts, moved_stmts) = stmts.split_at(stmts.len() - end_eq);
+        let (start_stmts, block_stmts) = block.stmts.split_at(start_eq);
+        let (block_stmts, end_stmts) = block_stmts.split_at(block_stmts.len() - end_eq);
+
+        // Scan start
+        let mut start_walker = UsedValueFinderVisitor::new(cx);
+        for stmt in start_stmts {
+            intravisit::walk_stmt(&mut start_walker, stmt);
+        }
+        let mut moved_syms = start_walker.def_symbols;
 
         // Scan block
-        let mut walker = SymbolFinderVisitor::new(cx);
+        let mut block_walker = UsedValueFinderVisitor::new(cx);
         for stmt in block_stmts {
-            intravisit::walk_stmt(&mut walker, stmt);
+            intravisit::walk_stmt(&mut block_walker, stmt);
         }
-        let mut block_defs = walker.defs;
+        let mut block_defs = block_walker.defs;
 
         // Scan moved stmts
         let mut moved_start: Option<usize> = None;
-        let mut walker = SymbolFinderVisitor::new(cx);
-        for (index, stmt) in moved_stmts.iter().enumerate() {
-            intravisit::walk_stmt(&mut walker, stmt);
+        let mut end_walker = UsedValueFinderVisitor::new(cx);
+        for (index, stmt) in end_stmts.iter().enumerate() {
+            intravisit::walk_stmt(&mut end_walker, stmt);
 
-            for value in &walker.uses {
+            for value in &end_walker.uses {
                 // Well we can't move this and all prev statements. So reset
                 if block_defs.contains(&value) {
                     moved_start = Some(index + 1);
-                    walker.defs.drain().for_each(|x| {
+                    end_walker.defs.drain().for_each(|x| {
                         block_defs.insert(x);
                     });
+
+                    end_walker.def_symbols.clear();
                 }
             }
 
-            walker.uses.clear();
+            end_walker.uses.clear();
         }
 
         if let Some(moved_start) = moved_start {
@@ -279,15 +303,65 @@ fn lint_same_then_else<'tcx>(
         }
 
         let end_linable = if let Some(expr) = block.expr {
-            intravisit::walk_expr(&mut walker, expr);
-            walker.uses.iter().any(|x| !block_defs.contains(x))
+            intravisit::walk_expr(&mut end_walker, expr);
+            end_walker.uses.iter().any(|x| !block_defs.contains(x))
         } else if end_eq == 0 {
             false
         } else {
             true
         };
 
-        emit_shared_code_in_if_blocks_lint(cx, start_eq, end_eq, end_linable, blocks, expr);
+        if end_linable {
+            end_walker.def_symbols.drain().for_each(|x| {
+                moved_syms.insert(x);
+            });
+        }
+
+        emit_shared_code_in_if_blocks_lint(
+            cx,
+            start_eq,
+            end_eq,
+            end_linable,
+            check_for_warn_of_moved_symbol(cx, &moved_syms, expr),
+            blocks,
+            expr,
+        );
+    }
+}
+
+fn check_for_warn_of_moved_symbol(
+    cx: &LateContext<'tcx>,
+    symbols: &FxHashSet<Symbol>,
+    if_expr: &'tcx Expr<'_>,
+) -> bool {
+    // Obs true as we include the current if block
+    if let Some(block) = get_enclosing_block(cx, if_expr.hir_id) {
+        let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
+
+        symbols
+            .iter()
+            .filter(|sym| !sym.as_str().starts_with('_'))
+            .any(move |sym| {
+                let mut walker = ContainsName {
+                    name: *sym,
+                    result: false,
+                };
+
+                // Scan block
+                block
+                    .stmts
+                    .iter()
+                    .filter(|stmt| !ignore_span.overlaps(stmt.span))
+                    .for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
+
+                if let Some(expr) = block.expr {
+                    intravisit::walk_expr(&mut walker, expr);
+                }
+
+                walker.result
+            })
+    } else {
+        false
     }
 }
 
@@ -296,6 +370,7 @@ fn emit_shared_code_in_if_blocks_lint(
     start_stmts: usize,
     end_stmts: usize,
     lint_end: bool,
+    warn_about_moved_symbol: bool,
     blocks: &[&Block<'tcx>],
     if_expr: &'tcx Expr<'_>,
 ) {
@@ -305,7 +380,9 @@ fn emit_shared_code_in_if_blocks_lint(
 
     // (help, span, suggestion)
     let mut suggestions: Vec<(&str, Span, String)> = vec![];
+    let mut add_expr_note = false;
 
+    // Construct suggestions
     if start_stmts > 0 {
         let block = blocks[0];
         let span_start = first_line_of_span(cx, if_expr.span).shrink_to_lo();
@@ -357,21 +434,29 @@ fn emit_shared_code_in_if_blocks_lint(
         }
 
         suggestions.push(("end", span, suggestion.to_string()));
+        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
     }
 
+    let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
+        if add_expr_note {
+            diag.note("The end suggestion probably needs some adjustments to use the expression result correctly.");
+        }
+
+        if warn_about_moved_symbol {
+            diag.warn("Some moved values might need to be renamed to avoid wrong references.");
+        }
+    };
+
+    // Emit lint
     if suggestions.len() == 1 {
         let (place_str, span, sugg) = suggestions.pop().unwrap();
         let msg = format!("All if blocks contain the same code at the {}", place_str);
         let help = format!("Consider moving the {} statements out like this", place_str);
-        span_lint_and_sugg(
-            cx,
-            SHARED_CODE_IN_IF_BLOCKS,
-            span,
-            msg.as_str(),
-            help.as_str(),
-            sugg,
-            Applicability::Unspecified,
-        );
+        span_lint_and_then(cx, SHARED_CODE_IN_IF_BLOCKS, span, msg.as_str(), |diag| {
+            diag.span_suggestion(span, help.as_str(), sugg, Applicability::Unspecified);
+
+            add_optional_msgs(diag);
+        });
     } else if suggestions.len() == 2 {
         let (_, end_span, end_sugg) = suggestions.pop().unwrap();
         let (_, start_span, start_sugg) = suggestions.pop().unwrap();
@@ -396,28 +481,39 @@ fn emit_shared_code_in_if_blocks_lint(
                     end_sugg,
                     Applicability::Unspecified,
                 );
+
+                add_optional_msgs(diag);
             },
         );
     }
 }
 
-pub struct SymbolFinderVisitor<'a, 'tcx> {
+/// This visitor collects HirIds and Symbols of defined symbols and HirIds of used values.
+struct UsedValueFinderVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
+
+    /// The `HirId`s of defined values in the scanned statements
     defs: FxHashSet<HirId>,
+
+    /// The Symbols of the defined symbols in the scanned statements
+    def_symbols: FxHashSet<Symbol>,
+
+    /// The `HirId`s of the used values
     uses: FxHashSet<HirId>,
 }
 
-impl<'a, 'tcx> SymbolFinderVisitor<'a, 'tcx> {
+impl<'a, 'tcx> UsedValueFinderVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
-        SymbolFinderVisitor {
+        UsedValueFinderVisitor {
             cx,
             defs: FxHashSet::default(),
+            def_symbols: FxHashSet::default(),
             uses: FxHashSet::default(),
         }
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for SymbolFinderVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for UsedValueFinderVisitor<'a, 'tcx> {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -427,6 +523,11 @@ impl<'a, 'tcx> Visitor<'tcx> for SymbolFinderVisitor<'a, 'tcx> {
     fn visit_local(&mut self, l: &'tcx rustc_hir::Local<'tcx>) {
         let local_id = l.pat.hir_id;
         self.defs.insert(local_id);
+
+        if let Some(sym) = l.pat.simple_ident() {
+            self.def_symbols.insert(sym.name);
+        }
+
         if let Some(expr) = l.init {
             intravisit::walk_expr(self, expr);
         }
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index ba98a2a2607..9afbf95a342 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -1366,7 +1366,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&casts::PTR_AS_PTR),
         LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
         LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
-        LintId::of(&copies::SHARED_CODE_IN_IF_BLOCKS),
         LintId::of(&copy_iterator::COPY_ITERATOR),
         LintId::of(&default::DEFAULT_TRAIT_ACCESS),
         LintId::of(&dereference::EXPLICIT_DEREF_METHODS),
@@ -2064,6 +2063,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
         LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
         LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
+        LintId::of(&copies::SHARED_CODE_IN_IF_BLOCKS),
         LintId::of(&disallowed_method::DISALLOWED_METHOD),
         LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
         LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs
index b736eeff6bf..7fd55151226 100644
--- a/clippy_lints/src/literal_representation.rs
+++ b/clippy_lints/src/literal_representation.rs
@@ -464,28 +464,32 @@ impl DecimalLiteralRepresentation {
             {
                 return Err(WarningType::DecimalRepresentation);
             }
+        } else if digits.len() < 4 {
+            // Lint for Literals with a hex-representation of 2 or 3 digits
+            let f = &digits[0..1]; // first digit
+            let s = &digits[1..]; // suffix
+
+            // Powers of 2
+            if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && s.chars().all(|c| c == '0'))
+                // Powers of 2 minus 1
+                || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && s.chars().all(|c| c == 'F'))
+            {
+                return Err(WarningType::DecimalRepresentation);
+            }
         } else {
+            // Lint for Literals with a hex-representation of 4 digits or more
             let f = &digits[0..1]; // first digit
             let m = &digits[1..digits.len() - 1]; // middle digits, except last
             let s = &digits[1..]; // suffix
-            if digits.len() < 4 {
-                // Powers of 2
-                if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && s.chars().all(|c| c == '0'))
-                    // Powers of 2 minus 1
-                    || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && s.chars().all(|c| c == 'F'))
-                {
-                    return Err(WarningType::DecimalRepresentation);
-                }
-            } else {
-                // Powers of 2 with a margin of +15/-16
-                if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0'))
-                    || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F'))
-                    // Lint for representations with only 0s and Fs, while allowing 7 as the first
-                    // digit
-                    || ((f.eq("7") || f.eq("F")) && s.chars().all(|c| c == '0' || c == 'F'))
-                {
-                    return Err(WarningType::DecimalRepresentation);
-                }
+
+            // Powers of 2 with a margin of +15/-16
+            if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0'))
+                || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F'))
+                // Lint for representations with only 0s and Fs, while allowing 7 as the first
+                // digit
+                || ((f.eq("7") || f.eq("F")) && s.chars().all(|c| c == '0' || c == 'F'))
+            {
+                return Err(WarningType::DecimalRepresentation);
             }
         }
 
diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr
index 941b92f23f3..b31eb46a982 100644
--- a/tests/ui/if_same_then_else2.stderr
+++ b/tests/ui/if_same_then_else2.stderr
@@ -27,7 +27,7 @@ LL | |     } else {
    |
    = note: `-D clippy::if-same-then-else` implied by `-D warnings`
 note: same as this
-  --> $DIR/if_same_then_else2.rs:21:12
+  --> $DIR/if_same_then_else2.rs:22:12
    |
 LL |       } else {
    |  ____________^
@@ -40,7 +40,7 @@ LL | |     }
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:33:13
+  --> $DIR/if_same_then_else2.rs:34:13
    |
 LL |       if true {
    |  _____________^
@@ -49,7 +49,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:35:12
+  --> $DIR/if_same_then_else2.rs:36:12
    |
 LL |       } else {
    |  ____________^
@@ -59,7 +59,7 @@ LL | |     }
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:40:13
+  --> $DIR/if_same_then_else2.rs:41:13
    |
 LL |       if true {
    |  _____________^
@@ -68,7 +68,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:42:12
+  --> $DIR/if_same_then_else2.rs:43:12
    |
 LL |       } else {
    |  ____________^
@@ -78,7 +78,7 @@ LL | |     }
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:90:21
+  --> $DIR/if_same_then_else2.rs:91:21
    |
 LL |       let _ = if true {
    |  _____________________^
@@ -87,7 +87,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:92:12
+  --> $DIR/if_same_then_else2.rs:93:12
    |
 LL |       } else {
    |  ____________^
@@ -97,7 +97,7 @@ LL | |     };
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:97:13
+  --> $DIR/if_same_then_else2.rs:98:13
    |
 LL |       if true {
    |  _____________^
@@ -106,7 +106,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:99:12
+  --> $DIR/if_same_then_else2.rs:100:12
    |
 LL |       } else {
    |  ____________^
@@ -116,7 +116,7 @@ LL | |     }
    | |_____^
 
 error: this `if` has identical blocks
-  --> $DIR/if_same_then_else2.rs:121:20
+  --> $DIR/if_same_then_else2.rs:122:20
    |
 LL |       } else if true {
    |  ____________________^
@@ -126,7 +126,7 @@ LL | |     } else {
    | |_____^
    |
 note: same as this
-  --> $DIR/if_same_then_else2.rs:124:12
+  --> $DIR/if_same_then_else2.rs:125:12
    |
 LL |       } else {
    |  ____________^
diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs b/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs
index a586a1c9d45..5392da7ac7a 100644
--- a/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs
+++ b/tests/ui/shared_code_in_if_blocks/shared_at_bot.rs
@@ -171,6 +171,25 @@ fn not_moveable_due_to_value_scope() {
     };
 }
 
+/// This should add a note to the lint msg since the moved expression is not `()`
+fn added_note_for_expression_use() -> u32 {
+    let x = 9;
+
+    let _ = if x == 7 {
+        x << 2
+    } else {
+        let _ = 6;
+        x << 2
+    };
+
+    if x == 9 {
+        x * 4
+    } else {
+        let _ = 17;
+        x * 4
+    }
+}
+
 #[rustfmt::skip]
 fn test_suggestion_with_weird_formatting() {
     let x = 9;
diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_bot.stderr b/tests/ui/shared_code_in_if_blocks/shared_at_bot.stderr
new file mode 100644
index 00000000000..62a95157d61
--- /dev/null
+++ b/tests/ui/shared_code_in_if_blocks/shared_at_bot.stderr
@@ -0,0 +1,131 @@
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:31:5
+   |
+LL | /         let result = false;
+LL | |         println!("Block end!");
+LL | |         result
+LL | |     };
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_bot.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly.
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     let result = false;
+LL |     println!("Block end!");
+LL |     result;
+   |
+
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:66:5
+   |
+LL | /         println!(
+LL | |             "I'm moveable because I know: `outer_scope_value`: '{}'",
+LL | |             outer_scope_value
+LL | |         );
+LL | |     }
+   | |_____^
+   |
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     println!(
+LL |         "I'm moveable because I know: `outer_scope_value`: '{}'",
+LL |         outer_scope_value
+LL |     );
+   |
+
+error: All if blocks contain the same code at the start
+  --> $DIR/shared_at_bot.rs:83:9
+   |
+LL | /         if x == 8 {
+LL | |             // No parent!!
+LL | |             println!("Hello World");
+   | |____________________________________^
+   |
+help: Consider moving the start statements out like this
+   |
+LL |         println!("Hello World");
+LL |         if x == 8 {
+   |
+
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:104:5
+   |
+LL | /         let later_used_value = "A string value";
+LL | |         println!("{}", later_used_value);
+LL | |         // I'm expecting a note about this
+LL | |     }
+   | |_____^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     let later_used_value = "A string value";
+LL |     println!("{}", later_used_value);
+   |
+
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:117:5
+   |
+LL | /         let simple_examples = "I now identify as a &str :)";
+LL | |         println!("This is the new simple_example: {}", simple_examples);
+LL | |     }
+   | |_____^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     let simple_examples = "I now identify as a &str :)";
+LL |     println!("This is the new simple_example: {}", simple_examples);
+   |
+
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:182:5
+   |
+LL | /         x << 2
+LL | |     };
+   | |_____^
+   |
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly.
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     x << 2;
+   |
+
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:189:5
+   |
+LL | /         x * 4
+LL | |     }
+   | |_____^
+   |
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly.
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     x * 4
+   |
+
+error: All if blocks contain the same code at the end
+  --> $DIR/shared_at_bot.rs:201:44
+   |
+LL |     if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
+   |                                            ^^^^^^^^^^^
+   |
+help: Consider moving the end statements out like this
+   |
+LL |     if x == 17 { b = 1; a = 0x99; } else { }
+LL |     a = 0x99;
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_top.stderr b/tests/ui/shared_code_in_if_blocks/shared_at_top.stderr
new file mode 100644
index 00000000000..c2bd8a070ed
--- /dev/null
+++ b/tests/ui/shared_code_in_if_blocks/shared_at_top.stderr
@@ -0,0 +1,83 @@
+error: All if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:10:5
+   |
+LL | /     if true {
+LL | |         println!("Hello World!");
+   | |_________________________________^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_top.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: Consider moving the start statements out like this
+   |
+LL |     println!("Hello World!");
+LL |     if true {
+   |
+
+error: All if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:19:5
+   |
+LL | /     if x == 0 {
+LL | |         let y = 9;
+LL | |         println!("The value y was set to: `{}`", y);
+LL | |         let _z = y;
+   | |___________________^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the start statements out like this
+   |
+LL |     let y = 9;
+LL |     println!("The value y was set to: `{}`", y);
+LL |     let _z = y;
+LL |     if x == 0 {
+   |
+
+error: All if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:40:5
+   |
+LL | /     let _ = if x == 7 {
+LL | |         let y = 16;
+   | |___________________^
+   |
+help: Consider moving the start statements out like this
+   |
+LL |     let y = 16;
+LL |     let _ = if x == 7 {
+   |
+
+error: All if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:58:5
+   |
+LL | /     if x == 10 {
+LL | |         let used_value_name = "Different type";
+LL | |         println!("Str: {}", used_value_name);
+   | |_____________________________________________^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the start statements out like this
+   |
+LL |     let used_value_name = "Different type";
+LL |     println!("Str: {}", used_value_name);
+LL |     if x == 10 {
+   |
+
+error: All if blocks contain the same code at the start
+  --> $DIR/shared_at_top.rs:72:5
+   |
+LL | /     if x == 11 {
+LL | |         let can_be_overridden = "Move me";
+LL | |         println!("I'm also moveable");
+   | |______________________________________^
+   |
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the start statements out like this
+   |
+LL |     let can_be_overridden = "Move me";
+LL |     println!("I'm also moveable");
+LL |     if x == 11 {
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs b/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs
index 70f969aaf2e..46a8f931aaf 100644
--- a/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs
+++ b/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs
@@ -87,4 +87,33 @@ fn complexer_example() {
     }
 }
 
+/// This should add a note to the lint msg since the moved expression is not `()`
+fn added_note_for_expression_use() -> u32 {
+    let x = 9;
+
+    let _ = if x == 7 {
+        let _ = 19;
+
+        let _splitter = 6;
+
+        x << 2
+    } else {
+        let _ = 19;
+
+        x << 2
+    };
+
+    if x == 9 {
+        let _ = 17;
+
+        let _splitter = 6;
+
+        x * 4
+    } else {
+        let _ = 17;
+
+        x * 4
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.stderr b/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.stderr
new file mode 100644
index 00000000000..1ba7211b469
--- /dev/null
+++ b/tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.stderr
@@ -0,0 +1,154 @@
+error: All if blocks contain the same code at the start and the end. Here at the start:
+  --> $DIR/shared_at_top_and_bot.rs:16:5
+   |
+LL | /     if x == 7 {
+LL | |         let t = 7;
+LL | |         let _overlap_start = t * 2;
+LL | |         let _overlap_end = 2 * t;
+   | |_________________________________^
+   |
+note: the lint level is defined here
+  --> $DIR/shared_at_top_and_bot.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: And here at the end:
+  --> $DIR/shared_at_top_and_bot.rs:28:5
+   |
+LL | /         let _u = 9;
+LL | |     }
+   | |_____^
+help: Consider moving the start statements out like this:
+   |
+LL |     let t = 7;
+LL |     let _overlap_start = t * 2;
+LL |     let _overlap_end = 2 * t;
+LL |     if x == 7 {
+   |
+help: And consider moving the end statements out like this:
+   |
+LL |     }
+LL |     let _u = 9;
+   |
+
+error: All if blocks contain the same code at the start and the end. Here at the start:
+  --> $DIR/shared_at_top_and_bot.rs:32:5
+   |
+LL | /     if x == 99 {
+LL | |         let r = 7;
+LL | |         let _overlap_start = r;
+LL | |         let _overlap_middle = r * r;
+   | |____________________________________^
+   |
+note: And here at the end:
+  --> $DIR/shared_at_top_and_bot.rs:43:5
+   |
+LL | /         let _overlap_end = r * r * r;
+LL | |         let z = "end";
+LL | |     }
+   | |_____^
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the start statements out like this:
+   |
+LL |     let r = 7;
+LL |     let _overlap_start = r;
+LL |     let _overlap_middle = r * r;
+LL |     if x == 99 {
+   |
+help: And consider moving the end statements out like this:
+   |
+LL |     }
+LL |     let _overlap_end = r * r * r;
+LL |     let z = "end";
+   |
+
+error: All if blocks contain the same code at the start and the end. Here at the start:
+  --> $DIR/shared_at_top_and_bot.rs:61:5
+   |
+LL | /     if (x > 7 && y < 13) || (x + y) % 2 == 1 {
+LL | |         let a = 0xcafe;
+LL | |         let b = 0xffff00ff;
+LL | |         let e_id = gen_id(a, b);
+   | |________________________________^
+   |
+note: And here at the end:
+  --> $DIR/shared_at_top_and_bot.rs:81:5
+   |
+LL | /         let pack = DataPack {
+LL | |             id: e_id,
+LL | |             name: "Player 1".to_string(),
+LL | |             some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90],
+LL | |         };
+LL | |         process_data(pack);
+LL | |     }
+   | |_____^
+   = warning: Some moved values might need to be renamed to avoid wrong references.
+help: Consider moving the start statements out like this:
+   |
+LL |     let a = 0xcafe;
+LL |     let b = 0xffff00ff;
+LL |     let e_id = gen_id(a, b);
+LL |     if (x > 7 && y < 13) || (x + y) % 2 == 1 {
+   |
+help: And consider moving the end statements out like this:
+   |
+LL |     }
+LL |     let pack = DataPack {
+LL |         id: e_id,
+LL |         name: "Player 1".to_string(),
+LL |         some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90],
+LL |     };
+ ...
+
+error: All if blocks contain the same code at the start and the end. Here at the start:
+  --> $DIR/shared_at_top_and_bot.rs:94:5
+   |
+LL | /     let _ = if x == 7 {
+LL | |         let _ = 19;
+   | |___________________^
+   |
+note: And here at the end:
+  --> $DIR/shared_at_top_and_bot.rs:103:5
+   |
+LL | /         x << 2
+LL | |     };
+   | |_____^
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly.
+help: Consider moving the start statements out like this:
+   |
+LL |     let _ = 19;
+LL |     let _ = if x == 7 {
+   |
+help: And consider moving the end statements out like this:
+   |
+LL |     }
+LL |     x << 2;
+   |
+
+error: All if blocks contain the same code at the start and the end. Here at the start:
+  --> $DIR/shared_at_top_and_bot.rs:106:5
+   |
+LL | /     if x == 9 {
+LL | |         let _ = 17;
+   | |___________________^
+   |
+note: And here at the end:
+  --> $DIR/shared_at_top_and_bot.rs:115:5
+   |
+LL | /         x * 4
+LL | |     }
+   | |_____^
+   = note: The end suggestion probably needs some adjustments to use the expression result correctly.
+help: Consider moving the start statements out like this:
+   |
+LL |     let _ = 17;
+LL |     if x == 9 {
+   |
+help: And consider moving the end statements out like this:
+   |
+LL |     }
+LL |     x * 4
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/shared_code_in_if_blocks/valid_if_blocks.stderr b/tests/ui/shared_code_in_if_blocks/valid_if_blocks.stderr
new file mode 100644
index 00000000000..003c060f072
--- /dev/null
+++ b/tests/ui/shared_code_in_if_blocks/valid_if_blocks.stderr
@@ -0,0 +1,107 @@
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:102:15
+   |
+LL |       if x == 0 {
+   |  _______________^
+LL | |         let u = 19;
+LL | |         println!("How are u today?");
+LL | |         let _ = "This is a string";
+LL | |     } else {
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/valid_if_blocks.rs:2:9
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: same as this
+  --> $DIR/valid_if_blocks.rs:106:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         let u = 19;
+LL | |         println!("How are u today?");
+LL | |         let _ = "This is a string";
+LL | |     }
+   | |_____^
+
+error: All if blocks contain the same code at the end
+  --> $DIR/valid_if_blocks.rs:125:5
+   |
+LL | /         let pet = Duck { num: 18 };
+LL | |         println!("{:?}", pet);
+LL | |     }
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/valid_if_blocks.rs:2:36
+   |
+LL | #![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: Consider moving the end statements out like this
+   |
+LL |     }
+LL |     let pet = Duck { num: 18 };
+LL |     println!("{:?}", pet);
+   |
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:130:23
+   |
+LL |     let _ = if x == 6 { 7 } else { 7 };
+   |                       ^^^^^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:130:34
+   |
+LL |     let _ = if x == 6 { 7 } else { 7 };
+   |                                  ^^^^^
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:136:23
+   |
+LL |       } else if x == 68 {
+   |  _______________________^
+LL | |         println!("I'm a doppelgänger");
+LL | |         // Don't listen to my clone below
+LL | |
+...  |
+LL | |         }
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:145:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         // Don't listen to my clone above
+LL | |         println!("I'm a doppelgänger");
+LL | |
+...  |
+LL | |         }
+LL | |     };
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/valid_if_blocks.rs:158:23
+   |
+LL |       } else if x == 68 {
+   |  _______________________^
+LL | |         println!("I'm a doppelgänger");
+LL | |         // Don't listen to my clone below
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/valid_if_blocks.rs:161:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         // Don't listen to my clone above
+LL | |         println!("I'm a doppelgänger");
+LL | |     }
+   | |_____^
+
+error: aborting due to 5 previous errors
+