diff options
| author | xFrednet <xFrednet@gmail.com> | 2021-01-16 20:37:50 +0100 |
|---|---|---|
| committer | xFrednet <xFrednet@gmail.com> | 2021-04-05 13:33:45 +0200 |
| commit | b1d26e544f10b814d9793294d0c05dd2ace5d0dc (patch) | |
| tree | 4995c31746d8021f48c1eb431acd5eebf8de7858 | |
| parent | 8efc6acc05387738313798069b8553d0ab9c92e5 (diff) | |
| download | rust-b1d26e544f10b814d9793294d0c05dd2ace5d0dc.tar.gz rust-b1d26e544f10b814d9793294d0c05dd2ace5d0dc.zip | |
Improved shared_code_in_if_blocks message and added test stderrs
| -rw-r--r-- | clippy_lints/src/copies.rs | 169 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/literal_representation.rs | 40 | ||||
| -rw-r--r-- | tests/ui/if_same_then_else2.stderr | 22 | ||||
| -rw-r--r-- | tests/ui/shared_code_in_if_blocks/shared_at_bot.rs | 19 | ||||
| -rw-r--r-- | tests/ui/shared_code_in_if_blocks/shared_at_bot.stderr | 131 | ||||
| -rw-r--r-- | tests/ui/shared_code_in_if_blocks/shared_at_top.stderr | 83 | ||||
| -rw-r--r-- | tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.rs | 29 | ||||
| -rw-r--r-- | tests/ui/shared_code_in_if_blocks/shared_at_top_and_bot.stderr | 154 | ||||
| -rw-r--r-- | tests/ui/shared_code_in_if_blocks/valid_if_blocks.stderr | 107 |
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(©_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 + |
