diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e5d1688e4a7..a00a69851f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5931,6 +5931,7 @@ Released 2018-09-13 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive +[`stacked_if_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#stacked_if_match [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc [`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core [`str_split_at_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_split_at_newline diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 16c64830e70d..11fbe4224eb2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -662,6 +662,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, crate::size_of_ref::SIZE_OF_REF_INFO, crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO, + crate::stacked_if_match::STACKED_IF_MATCH_INFO, crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3604090b68cc..d1acd339cbfc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -335,6 +335,7 @@ mod single_range_in_vec_init; mod size_of_in_element_count; mod size_of_ref; mod slow_vector_initialization; +mod stacked_if_match; mod std_instead_of_core; mod string_patterns; mod strings; @@ -942,5 +943,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); + store.register_late_pass(|_| Box::new(stacked_if_match::StackedIfMatch)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/stacked_if_match.rs b/clippy_lints/src/stacked_if_match.rs new file mode 100644 index 000000000000..744cb2f76b1e --- /dev/null +++ b/clippy_lints/src/stacked_if_match.rs @@ -0,0 +1,102 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::visitors::{for_each_expr, Descend}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::declare_lint_pass; +use std::ops::ControlFlow; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `if if` and `match match`. + /// + /// ### Why is this bad? + /// `if if` and `match match` are hard to read. + /// + /// ### Example + /// ```no_run + /// # let (a, b, c, d, e, f) = (1, 2, 3, 4, 5, 6); + /// if if a == b { + /// c == d + /// } else { + /// e == f + /// } { + /// println!("true"); + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let (a, b, c, d, e, f) = (1, 2, 3, 4, 5, 6); + /// let result = if a == b { + /// c == d + /// } else { + /// e == f + /// }; + /// + /// if result { + /// println!("true"); + /// } + /// ``` + #[clippy::version = "1.82.0"] + pub STACKED_IF_MATCH, + style, + "`if if` and `match match` that can be eliminated" +} + +declare_lint_pass!(StackedIfMatch => [STACKED_IF_MATCH]); + +impl<'tcx> LateLintPass<'tcx> for StackedIfMatch { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if expr.span.from_expansion() || in_external_macro(cx.sess(), expr.span) { + return; + } + + let Some((cond, keyword)) = (match expr.kind { + ExprKind::If(if_expr, _, _) => Some((if_expr, "if")), + ExprKind::Match(match_expr, _, MatchSource::Normal) => Some((match_expr, "match")), + _ => None, + }) else { + return; + }; + + let cond_snippet = snippet(cx, cond.span, ""); + if !cond_snippet.starts_with("if") && !cond_snippet.starts_with("match") { + return; + } + + for_each_expr(cx, cond, |sub_expr| { + if matches!(sub_expr.kind, ExprKind::DropTemps(..)) { + return ControlFlow::Continue(Descend::Yes); + } + + if !sub_expr.span.eq_ctxt(expr.span) || sub_expr.span.lo() != cond.span.lo() { + return ControlFlow::Continue(Descend::No); + } + + let sub_keyword = match sub_expr.kind { + ExprKind::If(..) => "if", + ExprKind::Match(.., MatchSource::Normal) => "match", + _ => "", + }; + + if keyword == sub_keyword { + let inner_snippet = snippet(cx, sub_expr.span, ".."); + span_lint_and_sugg( + cx, + STACKED_IF_MATCH, + expr.span.with_hi(sub_expr.span.hi()), + format!("avoid using `{keyword} {keyword}` by binding inner `{keyword}` with `let`"), + "try", + format!("let result = {inner_snippet}; {keyword} result"), + Applicability::MachineApplicable, + ); + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::Yes) + } + }); + } +} diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 3a3eee4c958b..a7050f22dca4 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -5,7 +5,8 @@ clippy::no_effect, clippy::toplevel_ref_arg, clippy::uninlined_format_args, - clippy::useless_vec + clippy::useless_vec, + clippy::stacked_if_match )] struct Point { diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index ff2f842ac39e..317a4b5cfe4a 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -5,7 +5,8 @@ clippy::no_effect, clippy::toplevel_ref_arg, clippy::uninlined_format_args, - clippy::useless_vec + clippy::useless_vec, + clippy::stacked_if_match )] struct Point { diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 19ab85180ad2..b5c1f60d4288 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:33:5 + --> tests/ui/match_single_binding.rs:34:5 | LL | / match (a, b, c) { LL | | (x, y, z) => { @@ -19,7 +19,7 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:39:5 + --> tests/ui/match_single_binding.rs:40:5 | LL | / match (a, b, c) { LL | | (x, y, z) => println!("{} {} {}", x, y, z), @@ -33,7 +33,7 @@ LL + println!("{} {} {}", x, y, z); | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:56:5 + --> tests/ui/match_single_binding.rs:57:5 | LL | / match a { LL | | _ => println!("whatever"), @@ -41,7 +41,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:60:5 + --> tests/ui/match_single_binding.rs:61:5 | LL | / match a { LL | | _ => { @@ -60,7 +60,7 @@ LL + } | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:67:5 + --> tests/ui/match_single_binding.rs:68:5 | LL | / match a { LL | | _ => { @@ -82,7 +82,7 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:77:5 + --> tests/ui/match_single_binding.rs:78:5 | LL | / match p { LL | | Point { x, y } => println!("Coords: ({}, {})", x, y), @@ -96,7 +96,7 @@ LL + println!("Coords: ({}, {})", x, y); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:81:5 + --> tests/ui/match_single_binding.rs:82:5 | LL | / match p { LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), @@ -110,7 +110,7 @@ LL + println!("Coords: ({}, {})", x1, y1); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:86:5 + --> tests/ui/match_single_binding.rs:87:5 | LL | / match x { LL | | ref r => println!("Got a reference to {}", r), @@ -124,7 +124,7 @@ LL + println!("Got a reference to {}", r); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:91:5 + --> tests/ui/match_single_binding.rs:92:5 | LL | / match x { LL | | ref mut mr => println!("Got a mutable reference to {}", mr), @@ -138,7 +138,7 @@ LL + println!("Got a mutable reference to {}", mr); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:95:5 + --> tests/ui/match_single_binding.rs:96:5 | LL | / let product = match coords() { LL | | Point { x, y } => x * y, @@ -152,7 +152,7 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:103:18 + --> tests/ui/match_single_binding.rs:104:18 | LL | .map(|i| match i.unwrap() { | __________________^ @@ -169,7 +169,7 @@ LL ~ }) | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:129:5 + --> tests/ui/match_single_binding.rs:130:5 | LL | / match x { LL | | // => @@ -178,7 +178,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> tests/ui/match_single_binding.rs:138:5 + --> tests/ui/match_single_binding.rs:139:5 | LL | / val = match val.split_at(idx) { LL | | (pre, suf) => { @@ -198,7 +198,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:151:16 + --> tests/ui/match_single_binding.rs:152:16 | LL | let _ = || match side_effects() { | ________________^ @@ -215,7 +215,7 @@ LL ~ }; | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:157:5 + --> tests/ui/match_single_binding.rs:158:5 | LL | / match r { LL | | x => match x { @@ -240,7 +240,7 @@ LL ~ }; | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:170:5 + --> tests/ui/match_single_binding.rs:171:5 | LL | / match 1 { LL | | _ => (), @@ -248,7 +248,7 @@ LL | | } | |_____^ help: consider using the match body instead: `();` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:174:13 + --> tests/ui/match_single_binding.rs:175:13 | LL | let a = match 1 { | _____________^ @@ -257,7 +257,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:178:5 + --> tests/ui/match_single_binding.rs:179:5 | LL | / match 1 { LL | | _ => side_effects(), @@ -265,7 +265,7 @@ LL | | } | |_____^ help: consider using the match body instead: `side_effects();` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:182:13 + --> tests/ui/match_single_binding.rs:183:13 | LL | let b = match 1 { | _____________^ @@ -274,7 +274,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:186:5 + --> tests/ui/match_single_binding.rs:187:5 | LL | / match 1 { LL | | _ => println!("1"), @@ -282,7 +282,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("1");` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:190:13 + --> tests/ui/match_single_binding.rs:191:13 | LL | let c = match 1 { | _____________^ @@ -291,7 +291,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `println!("1")` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:195:9 + --> tests/ui/match_single_binding.rs:196:9 | LL | / match 1 { LL | | _ => (), @@ -299,7 +299,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:198:9 + --> tests/ui/match_single_binding.rs:199:9 | LL | / match 1 { LL | | _ => side_effects(), @@ -307,7 +307,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:201:9 + --> tests/ui/match_single_binding.rs:202:9 | LL | / match 1 { LL | | _ => println!("1"), diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index 5673aa78c76a..2b1f943a51e7 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -1,6 +1,7 @@ #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] +#![allow(clippy::stacked_if_match)] fn main() { // Lint (additional curly braces needed, see #6572) diff --git a/tests/ui/match_single_binding2.rs b/tests/ui/match_single_binding2.rs index 575e7f5816b8..c533d5625636 100644 --- a/tests/ui/match_single_binding2.rs +++ b/tests/ui/match_single_binding2.rs @@ -1,6 +1,7 @@ #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] +#![allow(clippy::stacked_if_match)] fn main() { // Lint (additional curly braces needed, see #6572) diff --git a/tests/ui/match_single_binding2.stderr b/tests/ui/match_single_binding2.stderr index 38659596af1f..73aa0cf86c5b 100644 --- a/tests/ui/match_single_binding2.stderr +++ b/tests/ui/match_single_binding2.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> tests/ui/match_single_binding2.rs:17:36 + --> tests/ui/match_single_binding2.rs:18:36 | LL | Some((iter, _item)) => match iter.size_hint() { | ____________________________________^ @@ -18,7 +18,7 @@ LL ~ }, | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding2.rs:30:13 + --> tests/ui/match_single_binding2.rs:31:13 | LL | / match get_tup() { LL | | (a, b) => println!("a {:?} and b {:?}", a, b), @@ -32,7 +32,7 @@ LL + println!("a {:?} and b {:?}", a, b) | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding2.rs:41:5 + --> tests/ui/match_single_binding2.rs:42:5 | LL | / match side_effects() { LL | | _ => println!("Side effects"), @@ -46,7 +46,7 @@ LL + println!("Side effects"); | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding2.rs:48:5 + --> tests/ui/match_single_binding2.rs:49:5 | LL | / match match x { LL | | 0 => 1, diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 0db6fbfb7be9..2de8e1bd0399 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -2,7 +2,12 @@ //@no-rustfix #![warn(clippy::significant_drop_in_scrutinee)] #![allow(dead_code, unused_assignments)] -#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] +#![allow( + clippy::match_single_binding, + clippy::single_match, + clippy::uninlined_format_args, + clippy::stacked_if_match +)] use std::num::ParseIntError; use std::ops::Deref; diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index c0c93cd10c02..62030cbe70e7 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:55:11 + --> tests/ui/significant_drop_in_scrutinee.rs:60:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:143:11 + --> tests/ui/significant_drop_in_scrutinee.rs:148:11 | LL | match s.lock_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:166:11 + --> tests/ui/significant_drop_in_scrutinee.rs:171:11 | LL | match s.lock_m_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:216:11 + --> tests/ui/significant_drop_in_scrutinee.rs:221:11 | LL | match counter.temp_increment().len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:241:16 + --> tests/ui/significant_drop_in_scrutinee.rs:246:16 | LL | match (mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL ~ match (value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:252:22 + --> tests/ui/significant_drop_in_scrutinee.rs:257:22 | LL | match (true, mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL ~ match (true, value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:264:16 + --> tests/ui/significant_drop_in_scrutinee.rs:269:16 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:264:54 + --> tests/ui/significant_drop_in_scrutinee.rs:269:54 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:319:11 + --> tests/ui/significant_drop_in_scrutinee.rs:324:11 | LL | match mutex.lock().unwrap().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:328:15 + --> tests/ui/significant_drop_in_scrutinee.rs:333:15 | LL | match 1 < mutex.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL ~ match 1 < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:348:11 + --> tests/ui/significant_drop_in_scrutinee.rs:353:11 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL ~ match value < mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:348:44 + --> tests/ui/significant_drop_in_scrutinee.rs:353:44 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL ~ match mutex1.lock().unwrap().s.len() < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:361:11 + --> tests/ui/significant_drop_in_scrutinee.rs:366:11 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ LL ~ match value >= mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:361:45 + --> tests/ui/significant_drop_in_scrutinee.rs:366:45 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,7 +282,7 @@ LL ~ match mutex1.lock().unwrap().s.len() >= value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:398:11 + --> tests/ui/significant_drop_in_scrutinee.rs:403:11 | LL | match get_mutex_guard().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:417:11 + --> tests/ui/significant_drop_in_scrutinee.rs:422:11 | LL | match match i { | ___________^ @@ -334,7 +334,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:445:11 + --> tests/ui/significant_drop_in_scrutinee.rs:450:11 | LL | match if i > 1 { | ___________^ @@ -368,7 +368,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:501:11 + --> tests/ui/significant_drop_in_scrutinee.rs:506:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +386,7 @@ LL ~ match (&value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:551:11 + --> tests/ui/significant_drop_in_scrutinee.rs:556:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -405,7 +405,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:559:15 + --> tests/ui/significant_drop_in_scrutinee.rs:564:15 | LL | match i = mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -424,7 +424,7 @@ LL ~ match i = value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:567:11 + --> tests/ui/significant_drop_in_scrutinee.rs:572:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +443,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:575:16 + --> tests/ui/significant_drop_in_scrutinee.rs:580:16 | LL | match i += mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -462,7 +462,7 @@ LL ~ match i += value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:640:11 + --> tests/ui/significant_drop_in_scrutinee.rs:645:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:668:11 + --> tests/ui/significant_drop_in_scrutinee.rs:673:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -494,7 +494,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:731:11 + --> tests/ui/significant_drop_in_scrutinee.rs:736:11 | LL | match guard.take().len() { | ^^^^^^^^^^^^^^^^^^ @@ -510,7 +510,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:757:16 + --> tests/ui/significant_drop_in_scrutinee.rs:762:16 | LL | for val in mutex.lock().unwrap().copy_old_lifetime() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -526,7 +526,7 @@ LL ~ for val in value { | error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:797:17 + --> tests/ui/significant_drop_in_scrutinee.rs:802:17 | LL | for val in [mutex.lock().unwrap()[0], 2] { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -542,7 +542,7 @@ LL ~ for val in [value, 2] { | error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression - --> tests/ui/significant_drop_in_scrutinee.rs:807:24 + --> tests/ui/significant_drop_in_scrutinee.rs:812:24 | LL | if let Some(val) = mutex.lock().unwrap().first().copied() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -558,7 +558,7 @@ LL ~ if let Some(val) = value { | error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression - --> tests/ui/significant_drop_in_scrutinee.rs:823:27 + --> tests/ui/significant_drop_in_scrutinee.rs:828:27 | LL | while let Some(val) = mutex.lock().unwrap().pop() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/stacked_if_match.fixed b/tests/ui/stacked_if_match.fixed new file mode 100644 index 000000000000..69e1bd984f9b --- /dev/null +++ b/tests/ui/stacked_if_match.fixed @@ -0,0 +1,144 @@ +#![warn(clippy::stacked_if_match)] +#![allow(unused)] + +fn stacked_if() { + let x = 0; + let result = if x == 1 { x == 2 } else { x == 3 }; if result { + println!("true"); + } + + let result = if x == 1 { 2 } else { 3 }; if result == 4 { + println!("true"); + } + + let result = if x == 1 { + let y = 2; + y == 2 + } else { + let z = 3; + z == 3 + }; if result { + println!("true"); + } +} + +fn stacked_match() { + let x = 0; + let result = match x { + 1 => 2, + _ => 3, + }; match result { + 1 => {}, + 2 => {}, + _ => {}, + } + + let result = match x { + 1 => 2, + _ => 3, + }; match result + 1 + { + 1 => {}, + 2 => {}, + _ => {}, + } +} + +fn if_no_lint() { + let x = 0; + + if (if x == 1 { x == 2 } else { x == 3 }) { + println!("true"); + } + + if 1 == if x == 1 { 1 } else { 2 } { + println!("true"); + } +} + +fn match_no_lint() { + let x = 0; + match (match x { + 1 => 2, + _ => 3, + }) { + 1 => {}, + 2 => {}, + _ => {}, + } + + match 1 + match x { + 1 => 2, + _ => 3, + } { + 1 => {}, + 2 => {}, + _ => {}, + } +} + +fn if_match_no_lint() { + let x = 0; + if match x { + 1 => 2, + _ => 3, + } == 4 + { + println!("true"); + } +} + +fn match_if_no_lint() { + let x = 0; + match if x == 1 { + let y = 2; + y + 1 + } else { + let z = 3; + z + 1 + } { + 1 => {}, + 2 => {}, + _ => {}, + } +} + +macro_rules! if_macro { + ($var:ident) => { + if $var == 1 { true } else { false } + }; +} + +macro_rules! match_macro { + ($var:ident) => { + match $var { + 1 => 2, + _ => 3, + } + }; +} + +macro_rules! if_if_macro { + () => { + if if true { true } else { false } { + println!("true"); + } + }; +} + +fn macro_no_lint() { + let x = 0; + if if_macro!(x) { + println!("true"); + } + + match match_macro!(x) { + 1 => {}, + 2 => {}, + _ => {}, + } + + if_if_macro!(); +} + +fn main() {} diff --git a/tests/ui/stacked_if_match.rs b/tests/ui/stacked_if_match.rs new file mode 100644 index 000000000000..dca4c1bc5058 --- /dev/null +++ b/tests/ui/stacked_if_match.rs @@ -0,0 +1,144 @@ +#![warn(clippy::stacked_if_match)] +#![allow(unused)] + +fn stacked_if() { + let x = 0; + if if x == 1 { x == 2 } else { x == 3 } { + println!("true"); + } + + if if x == 1 { 2 } else { 3 } == 4 { + println!("true"); + } + + if if x == 1 { + let y = 2; + y == 2 + } else { + let z = 3; + z == 3 + } { + println!("true"); + } +} + +fn stacked_match() { + let x = 0; + match match x { + 1 => 2, + _ => 3, + } { + 1 => {}, + 2 => {}, + _ => {}, + } + + match match x { + 1 => 2, + _ => 3, + } + 1 + { + 1 => {}, + 2 => {}, + _ => {}, + } +} + +fn if_no_lint() { + let x = 0; + + if (if x == 1 { x == 2 } else { x == 3 }) { + println!("true"); + } + + if 1 == if x == 1 { 1 } else { 2 } { + println!("true"); + } +} + +fn match_no_lint() { + let x = 0; + match (match x { + 1 => 2, + _ => 3, + }) { + 1 => {}, + 2 => {}, + _ => {}, + } + + match 1 + match x { + 1 => 2, + _ => 3, + } { + 1 => {}, + 2 => {}, + _ => {}, + } +} + +fn if_match_no_lint() { + let x = 0; + if match x { + 1 => 2, + _ => 3, + } == 4 + { + println!("true"); + } +} + +fn match_if_no_lint() { + let x = 0; + match if x == 1 { + let y = 2; + y + 1 + } else { + let z = 3; + z + 1 + } { + 1 => {}, + 2 => {}, + _ => {}, + } +} + +macro_rules! if_macro { + ($var:ident) => { + if $var == 1 { true } else { false } + }; +} + +macro_rules! match_macro { + ($var:ident) => { + match $var { + 1 => 2, + _ => 3, + } + }; +} + +macro_rules! if_if_macro { + () => { + if if true { true } else { false } { + println!("true"); + } + }; +} + +fn macro_no_lint() { + let x = 0; + if if_macro!(x) { + println!("true"); + } + + match match_macro!(x) { + 1 => {}, + 2 => {}, + _ => {}, + } + + if_if_macro!(); +} + +fn main() {} diff --git a/tests/ui/stacked_if_match.stderr b/tests/ui/stacked_if_match.stderr new file mode 100644 index 000000000000..5dcb40610c6c --- /dev/null +++ b/tests/ui/stacked_if_match.stderr @@ -0,0 +1,74 @@ +error: avoid using `if if` by binding inner `if` with `let` + --> tests/ui/stacked_if_match.rs:6:5 + | +LL | if if x == 1 { x == 2 } else { x == 3 } { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `let result = if x == 1 { x == 2 } else { x == 3 }; if result` + | + = note: `-D clippy::stacked-if-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::stacked_if_match)]` + +error: avoid using `if if` by binding inner `if` with `let` + --> tests/ui/stacked_if_match.rs:10:5 + | +LL | if if x == 1 { 2 } else { 3 } == 4 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `let result = if x == 1 { 2 } else { 3 }; if result` + +error: avoid using `if if` by binding inner `if` with `let` + --> tests/ui/stacked_if_match.rs:14:5 + | +LL | / if if x == 1 { +LL | | let y = 2; +LL | | y == 2 +LL | | } else { +LL | | let z = 3; +LL | | z == 3 +LL | | } { + | |_____^ + | +help: try + | +LL ~ let result = if x == 1 { +LL + let y = 2; +LL + y == 2 +LL + } else { +LL + let z = 3; +LL + z == 3 +LL ~ }; if result { + | + +error: avoid using `match match` by binding inner `match` with `let` + --> tests/ui/stacked_if_match.rs:27:5 + | +LL | / match match x { +LL | | 1 => 2, +LL | | _ => 3, +LL | | } { + | |_____^ + | +help: try + | +LL ~ let result = match x { +LL + 1 => 2, +LL + _ => 3, +LL ~ }; match result { + | + +error: avoid using `match match` by binding inner `match` with `let` + --> tests/ui/stacked_if_match.rs:36:5 + | +LL | / match match x { +LL | | 1 => 2, +LL | | _ => 3, +LL | | } + 1 + | |_____^ + | +help: try + | +LL ~ let result = match x { +LL + 1 => 2, +LL + _ => 3, +LL ~ }; match result + 1 + | + +error: aborting due to 5 previous errors +