From 0ab823c509897ce2f516feb760fe1bf02cf77443 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 26 Aug 2019 18:34:30 +0200 Subject: [PATCH 1/9] Rework suggestion generation of `unit_arg` lint --- clippy_lints/src/types.rs | 42 ++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 3ac99e246..8fcca4b7b 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -779,6 +779,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { match expr.kind { ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => { + let mut args_to_recover = vec![]; for arg in args { if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { if let ExprKind::Match(.., match_source) = &arg.kind { @@ -787,17 +788,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } } - span_lint_and_sugg( - cx, - UNIT_ARG, - arg.span, - "passing a unit value to a function", - "if you intended to pass a unit value, use a unit literal instead", - "()".to_string(), - Applicability::MaybeIncorrect, - ); + args_to_recover.push(arg); } } + if !args_to_recover.is_empty() { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + "move the expressions in front of the call...", + format!( + "{} ", + args_to_recover + .iter() + .map(|arg| { + format!( + "{};", + snippet_with_applicability(cx, arg.span, "..", &mut applicability) + ) + }) + .collect::>() + .join(" ") + ), + applicability, + ); + db.multipart_suggestion( + "...and use unit literals instead", + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), + applicability, + ); + }); + } }, _ => (), } From 380d941a045dc213ae28807d74fc32d1b1841e22 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 26 Aug 2019 19:35:25 +0200 Subject: [PATCH 2/9] Adapt stderr and fixed files --- tests/ui/unit_arg.fixed | 29 +++++++--- tests/ui/unit_arg.rs | 10 +++- tests/ui/unit_arg.stderr | 112 ++++++++++++++++++++++++++++++--------- 3 files changed, 118 insertions(+), 33 deletions(-) diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed index a739cf7ad..67c6bdf88 100644 --- a/tests/ui/unit_arg.fixed +++ b/tests/ui/unit_arg.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(unused_braces, clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] use std::fmt::Debug; @@ -21,13 +21,21 @@ impl Bar { } fn bad() { - foo(()); - foo(()); - foo(()); - foo(()); - foo3((), 2, 2); + {}; foo(()); + { + 1; + }; foo(()); + foo(1); foo(()); + { + foo(1); + foo(2); + }; foo(()); + {}; foo3((), 2, 2); let b = Bar; - b.bar(()); + { + 1; + }; b.bar(()); + foo(0); foo(1); taking_multiple_units((), ()); } fn ok() { @@ -58,6 +66,13 @@ mod issue_2945 { } } +#[allow(dead_code)] +fn returning_expr() -> Option<()> { + foo(1); Some(()) +} + +fn taking_multiple_units(a: (), b: ()) {} + fn main() { bad(); ok(); diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index d90c49f79..c6e465b2e 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(unused_braces, clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] use std::fmt::Debug; @@ -35,6 +35,7 @@ fn bad() { b.bar({ 1; }); + taking_multiple_units(foo(0), foo(1)); } fn ok() { @@ -65,6 +66,13 @@ mod issue_2945 { } } +#[allow(dead_code)] +fn returning_expr() -> Option<()> { + Some(foo(1)) +} + +fn taking_multiple_units(a: (), b: ()) {} + fn main() { bad(); ok(); diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 21ccc684e..ce9ab2f12 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,79 +1,141 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:9 + --> $DIR/unit_arg.rs:24:5 | LL | foo({}); - | ^^ + | ^^^^^^^ | = note: `-D clippy::unit-arg` implied by `-D warnings` -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | {}; foo({}); + | ^^^ +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:25:9 + --> $DIR/unit_arg.rs:25:5 | -LL | foo({ - | _________^ +LL | / foo({ LL | | 1; LL | | }); - | |_____^ + | |______^ | -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | { +LL | 1; +LL | }; foo({ + | +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:9 + --> $DIR/unit_arg.rs:28:5 | LL | foo(foo(1)); - | ^^^^^^ + | ^^^^^^^^^^^ | -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | foo(1); foo(foo(1)); + | ^^^^^^^ +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:9 + --> $DIR/unit_arg.rs:29:5 | -LL | foo({ - | _________^ +LL | / foo({ LL | | foo(1); LL | | foo(2); LL | | }); - | |_____^ + | |______^ | -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | { +LL | foo(1); +LL | foo(2); +LL | }; foo({ + | +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:10 + --> $DIR/unit_arg.rs:33:5 | LL | foo3({}, 2, 2); - | ^^ + | ^^^^^^^^^^^^^^ | -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | {}; foo3({}, 2, 2); + | ^^^ +help: ...and use unit literals instead | LL | foo3((), 2, 2); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:35:11 + --> $DIR/unit_arg.rs:35:5 | -LL | b.bar({ - | ___________^ +LL | / b.bar({ LL | | 1; LL | | }); - | |_____^ + | |______^ | -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | { +LL | 1; +LL | }; b.bar({ + | +help: ...and use unit literals instead | LL | b.bar(()); | ^^ -error: aborting due to 6 previous errors +error: passing a unit value to a function + --> $DIR/unit_arg.rs:38:5 + | +LL | taking_multiple_units(foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(0); foo(1); taking_multiple_units(foo(0), foo(1)); + | ^^^^^^^^^^^^^^^ +help: ...and use unit literals instead + | +LL | taking_multiple_units((), foo(1)); + | ^^ +help: ...and use unit literals instead + | +LL | taking_multiple_units(foo(0), ()); + | ^^ + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:71:5 + | +LL | Some(foo(1)) + | ^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(1); Some(foo(1)) + | ^^^^^^^ +help: ...and use unit literals instead + | +LL | Some(()) + | ^^ + +error: aborting due to 8 previous errors From a1a1a4b82a35b810570dbf7d2ee7f00896bee232 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 26 Aug 2019 21:43:29 +0200 Subject: [PATCH 3/9] Use multiple span_suggestions instead of multipart_suggestion multipart suggestions aren't autofixable by rustfix yet --- clippy_lints/src/types.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 8fcca4b7b..3fbea7775 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -812,14 +812,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { ), applicability, ); - db.multipart_suggestion( - "...and use unit literals instead", - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), - applicability, - ); + for arg in args_to_recover { + db.span_suggestion( + arg.span, + "...and use unit literals instead", + "()".to_string(), + applicability, + ); + } }); } }, From 0f69cafc2dd77d573e24870887a4a13cfe50515a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 17 Feb 2020 18:10:59 +0100 Subject: [PATCH 4/9] Rework suggestion generation and use multipart_suggestion again --- clippy_lints/src/types.rs | 55 +++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 3fbea7775..c95bd5d72 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -794,32 +794,43 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { if !args_to_recover.is_empty() { let mut applicability = Applicability::MachineApplicable; span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { + let sugg = args_to_recover + .iter() + .enumerate() + .map(|(i, arg)| { + let indent = if i == 0 { + 0 + } else { + indent_of(cx, expr.span).unwrap_or(0) + }; + format!( + "{}{};", + " ".repeat(indent), + snippet_block_with_applicability( + cx, + arg.span, + "..", + Some(expr.span), + &mut applicability + ) + ) + }) + .collect::>() + .join("\n"); db.span_suggestion( expr.span.with_hi(expr.span.lo()), - "move the expressions in front of the call...", - format!( - "{} ", - args_to_recover - .iter() - .map(|arg| { - format!( - "{};", - snippet_with_applicability(cx, arg.span, "..", &mut applicability) - ) - }) - .collect::>() - .join(" ") - ), + &format!("{}move the expressions in front of the call...", or), + format!("{}\n", sugg), + applicability, + ); + db.multipart_suggestion( + "...and use unit literals instead", + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), applicability, ); - for arg in args_to_recover { - db.span_suggestion( - arg.span, - "...and use unit literals instead", - "()".to_string(), - applicability, - ); - } }); } }, From f9c325f5b657e0c37ba2016a51cddbeab7f7693f Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 17 Feb 2020 18:11:50 +0100 Subject: [PATCH 5/9] Suggest to remove the semicolon of the last stmt in a block --- clippy_lints/src/types.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c95bd5d72..51d7d9b3a 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -794,6 +794,36 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { if !args_to_recover.is_empty() { let mut applicability = Applicability::MachineApplicable; span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { + let mut or = ""; + args_to_recover + .iter() + .filter_map(|arg| { + if_chain! { + if let ExprKind::Block(block, _) = arg.kind; + if block.expr.is_none(); + if let Some(last_stmt) = block.stmts.iter().last(); + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let Some(snip) = snippet_opt(cx, last_expr.span); + then { + Some(( + last_stmt.span, + snip, + )) + } + else { + None + } + } + }) + .for_each(|(span, sugg)| { + db.span_suggestion( + span, + "remove the semicolon from the last statement in the block", + sugg, + Applicability::MaybeIncorrect, + ); + or = "or "; + }); let sugg = args_to_recover .iter() .enumerate() From 4c9cefa12232aa0224b1680f51654fe10f5cf3b7 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 18 Feb 2020 09:51:52 +0100 Subject: [PATCH 6/9] Move linting out in its own function --- clippy_lints/src/types.rs | 171 ++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 80 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 51d7d9b3a..6866635b9 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -779,89 +779,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { match expr.kind { ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => { - let mut args_to_recover = vec![]; - for arg in args { - if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { - if let ExprKind::Match(.., match_source) = &arg.kind { - if *match_source == MatchSource::TryDesugar { - continue; + let args_to_recover = args + .iter() + .filter(|arg| { + if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { + if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind { + false + } else { + true } + } else { + false } - - args_to_recover.push(arg); - } - } + }) + .collect::>(); if !args_to_recover.is_empty() { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { - let mut or = ""; - args_to_recover - .iter() - .filter_map(|arg| { - if_chain! { - if let ExprKind::Block(block, _) = arg.kind; - if block.expr.is_none(); - if let Some(last_stmt) = block.stmts.iter().last(); - if let StmtKind::Semi(last_expr) = last_stmt.kind; - if let Some(snip) = snippet_opt(cx, last_expr.span); - then { - Some(( - last_stmt.span, - snip, - )) - } - else { - None - } - } - }) - .for_each(|(span, sugg)| { - db.span_suggestion( - span, - "remove the semicolon from the last statement in the block", - sugg, - Applicability::MaybeIncorrect, - ); - or = "or "; - }); - let sugg = args_to_recover - .iter() - .enumerate() - .map(|(i, arg)| { - let indent = if i == 0 { - 0 - } else { - indent_of(cx, expr.span).unwrap_or(0) - }; - format!( - "{}{};", - " ".repeat(indent), - snippet_block_with_applicability( - cx, - arg.span, - "..", - Some(expr.span), - &mut applicability - ) - ) - }) - .collect::>() - .join("\n"); - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expressions in front of the call...", or), - format!("{}\n", sugg), - applicability, - ); - db.multipart_suggestion( - "...and use unit literals instead", - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), - applicability, - ); - }); + lint_unit_args(cx, expr, &args_to_recover); } }, _ => (), @@ -869,6 +802,84 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } } +fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + let (singular, plural) = if args_to_recover.len() > 1 { + ("", "s") + } else { + ("a ", "") + }; + span_lint_and_then( + cx, + UNIT_ARG, + expr.span, + &format!("passing {}unit value{} to a function", singular, plural), + |db| { + let mut or = ""; + args_to_recover + .iter() + .filter_map(|arg| { + if_chain! { + if let ExprKind::Block(block, _) = arg.kind; + if block.expr.is_none(); + if let Some(last_stmt) = block.stmts.iter().last(); + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let Some(snip) = snippet_opt(cx, last_expr.span); + then { + Some(( + last_stmt.span, + snip, + )) + } + else { + None + } + } + }) + .for_each(|(span, sugg)| { + db.span_suggestion( + span, + "remove the semicolon from the last statement in the block", + sugg, + Applicability::MaybeIncorrect, + ); + or = "or "; + }); + let sugg = args_to_recover + .iter() + .enumerate() + .map(|(i, arg)| { + let indent = if i == 0 { + 0 + } else { + indent_of(cx, expr.span).unwrap_or(0) + }; + format!( + "{}{};", + " ".repeat(indent), + snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) + ) + }) + .collect::>() + .join("\n"); + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + &format!("{}move the expression{} in front of the call...", or, plural), + format!("{}\n", sugg), + applicability, + ); + db.multipart_suggestion( + &format!("...and use {}unit literal{} instead", singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), + applicability, + ); + }, + ); +} + fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::DesugaringKind; if let ExprKind::Call(ref callee, _) = expr.kind { From 6d15a149640e5647ce232690d54b540346fa1641 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 17 Feb 2020 18:12:01 +0100 Subject: [PATCH 7/9] Update test files --- tests/ui/unit_arg.fixed | 79 ------------------ tests/ui/unit_arg.rs | 15 +++- tests/ui/unit_arg.stderr | 170 +++++++++++++++++++++++++++------------ 3 files changed, 134 insertions(+), 130 deletions(-) delete mode 100644 tests/ui/unit_arg.fixed diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed deleted file mode 100644 index 67c6bdf88..000000000 --- a/tests/ui/unit_arg.fixed +++ /dev/null @@ -1,79 +0,0 @@ -// run-rustfix -#![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] - -use std::fmt::Debug; - -fn foo(t: T) { - println!("{:?}", t); -} - -fn foo3(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -struct Bar; - -impl Bar { - fn bar(&self, t: T) { - println!("{:?}", t); - } -} - -fn bad() { - {}; foo(()); - { - 1; - }; foo(()); - foo(1); foo(()); - { - foo(1); - foo(2); - }; foo(()); - {}; foo3((), 2, 2); - let b = Bar; - { - 1; - }; b.bar(()); - foo(0); foo(1); taking_multiple_units((), ()); -} - -fn ok() { - foo(()); - foo(1); - foo({ 1 }); - foo3("a", 3, vec![3]); - let b = Bar; - b.bar({ 1 }); - b.bar(()); - question_mark(); -} - -fn question_mark() -> Result<(), ()> { - Ok(Ok(())?)?; - Ok(Ok(()))??; - Ok(()) -} - -#[allow(dead_code)] -mod issue_2945 { - fn unit_fn() -> Result<(), i32> { - Ok(()) - } - - fn fallible() -> Result<(), i32> { - Ok(unit_fn()?) - } -} - -#[allow(dead_code)] -fn returning_expr() -> Option<()> { - foo(1); Some(()) -} - -fn taking_multiple_units(a: (), b: ()) {} - -fn main() { - bad(); - ok(); -} diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index c6e465b2e..7d1b99fed 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,3 @@ -// run-rustfix #![warn(clippy::unit_arg)] #![allow(clippy::no_effect, unused_must_use, unused_variables)] @@ -36,6 +35,20 @@ fn bad() { 1; }); taking_multiple_units(foo(0), foo(1)); + taking_multiple_units(foo(0), { + foo(1); + foo(2); + }); + taking_multiple_units( + { + foo(0); + foo(1); + }, + { + foo(2); + foo(3); + }, + ); } fn ok() { diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index ce9ab2f12..145b3c62b 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,34 +1,53 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:5 + --> $DIR/unit_arg.rs:23:5 | LL | foo({}); | ^^^^^^^ | = note: `-D clippy::unit-arg` implied by `-D warnings` -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | {}; foo({}); - | ^^^ -help: ...and use unit literals instead +LL | {}; + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:25:5 + --> $DIR/unit_arg.rs:24:5 | LL | / foo({ LL | | 1; LL | | }); | |______^ | -help: move the expressions in front of the call... +help: remove the semicolon from the last statement in the block + | +LL | 1 + | +help: or move the expression in front of the call... | LL | { LL | 1; -LL | }; foo({ +LL | }; | -help: ...and use unit literals instead +help: ...and use a unit literal instead + | +LL | foo(()); + | ^^ + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:27:5 + | +LL | foo(foo(1)); + | ^^^^^^^^^^^ + | +help: move the expression in front of the call... + | +LL | foo(1); + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ @@ -36,106 +55,157 @@ LL | foo(()); error: passing a unit value to a function --> $DIR/unit_arg.rs:28:5 | -LL | foo(foo(1)); - | ^^^^^^^^^^^ - | -help: move the expressions in front of the call... - | -LL | foo(1); foo(foo(1)); - | ^^^^^^^ -help: ...and use unit literals instead - | -LL | foo(()); - | ^^ - -error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:5 - | LL | / foo({ LL | | foo(1); LL | | foo(2); LL | | }); | |______^ | -help: move the expressions in front of the call... +help: remove the semicolon from the last statement in the block + | +LL | foo(2) + | +help: or move the expression in front of the call... | LL | { LL | foo(1); LL | foo(2); -LL | }; foo({ +LL | }; | -help: ...and use unit literals instead +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:5 + --> $DIR/unit_arg.rs:32:5 | LL | foo3({}, 2, 2); | ^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | {}; foo3({}, 2, 2); - | ^^^ -help: ...and use unit literals instead +LL | {}; + | +help: ...and use a unit literal instead | LL | foo3((), 2, 2); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:35:5 + --> $DIR/unit_arg.rs:34:5 | LL | / b.bar({ LL | | 1; LL | | }); | |______^ | -help: move the expressions in front of the call... +help: remove the semicolon from the last statement in the block + | +LL | 1 + | +help: or move the expression in front of the call... | LL | { LL | 1; -LL | }; b.bar({ +LL | }; | -help: ...and use unit literals instead +help: ...and use a unit literal instead | LL | b.bar(()); | ^^ -error: passing a unit value to a function - --> $DIR/unit_arg.rs:38:5 +error: passing unit values to a function + --> $DIR/unit_arg.rs:37:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: move the expressions in front of the call... | -LL | foo(0); foo(1); taking_multiple_units(foo(0), foo(1)); - | ^^^^^^^^^^^^^^^ +LL | foo(0); +LL | foo(1); + | help: ...and use unit literals instead | -LL | taking_multiple_units((), foo(1)); - | ^^ +LL | taking_multiple_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg.rs:38:5 + | +LL | / taking_multiple_units(foo(0), { +LL | | foo(1); +LL | | foo(2); +LL | | }); + | |______^ + | +help: remove the semicolon from the last statement in the block + | +LL | foo(2) + | +help: or move the expressions in front of the call... + | +LL | foo(0); +LL | { +LL | foo(1); +LL | foo(2); +LL | }; + | help: ...and use unit literals instead | -LL | taking_multiple_units(foo(0), ()); - | ^^ +LL | taking_multiple_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg.rs:42:5 + | +LL | / taking_multiple_units( +LL | | { +LL | | foo(0); +LL | | foo(1); +... | +LL | | }, +LL | | ); + | |_____^ + | +help: remove the semicolon from the last statement in the block + | +LL | foo(1) + | +help: remove the semicolon from the last statement in the block + | +LL | foo(3) + | +help: or move the expressions in front of the call... + | +LL | { +LL | foo(0); +LL | foo(1); +LL | }; +LL | { +LL | foo(2); + ... +help: ...and use unit literals instead + | +LL | (), +LL | (), + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:71:5 + --> $DIR/unit_arg.rs:84:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | foo(1); Some(foo(1)) - | ^^^^^^^ -help: ...and use unit literals instead +LL | foo(1); + | +help: ...and use a unit literal instead | LL | Some(()) | ^^ -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors From a9cde3a804808e82402888a20878053404a8eded Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 31 May 2020 18:45:16 +0200 Subject: [PATCH 8/9] Don't suggest to move empty blocks --- clippy_lints/src/types.rs | 43 +++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6866635b9..5ca30d598 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -10,7 +10,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, + BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; @@ -29,10 +29,10 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, is_type_diagnostic_item, + clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + qpath_res, same_tys, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { @@ -847,6 +847,7 @@ fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[ }); let sugg = args_to_recover .iter() + .filter(|arg| !is_empty_block(arg)) .enumerate() .map(|(i, arg)| { let indent = if i == 0 { @@ -860,16 +861,20 @@ fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[ snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) ) }) - .collect::>() - .join("\n"); - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expression{} in front of the call...", or, plural), - format!("{}\n", sugg), - applicability, - ); + .collect::>(); + let mut and = ""; + if !sugg.is_empty() { + let plural = if sugg.len() > 1 { "s" } else { "" }; + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + &format!("{}move the expression{} in front of the call...", or, plural), + format!("{}\n", sugg.join("\n")), + applicability, + ); + and = "...and " + } db.multipart_suggestion( - &format!("...and use {}unit literal{} instead", singular, plural), + &format!("{}use {}unit literal{} instead", and, singular, plural), args_to_recover .iter() .map(|arg| (arg.span, "()".to_string())) @@ -880,6 +885,18 @@ fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[ ); } +fn is_empty_block(expr: &Expr<'_>) -> bool { + matches!( + expr.kind, + ExprKind::Block( + Block { + stmts: &[], expr: None, .. + }, + _, + ) + ) +} + fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::DesugaringKind; if let ExprKind::Call(ref callee, _) = expr.kind { From 77dd0ea62aa6a2af70da4c5e05de064eee182a6c Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 31 May 2020 19:29:36 +0200 Subject: [PATCH 9/9] Add tests for empty blocks --- tests/ui/unit_arg.rs | 2 -- tests/ui/unit_arg.stderr | 46 +++++------------------- tests/ui/unit_arg_empty_blocks.rs | 26 ++++++++++++++ tests/ui/unit_arg_empty_blocks.stderr | 51 +++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 tests/ui/unit_arg_empty_blocks.rs create mode 100644 tests/ui/unit_arg_empty_blocks.stderr diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 7d1b99fed..2992abae7 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -20,7 +20,6 @@ impl Bar { } fn bad() { - foo({}); foo({ 1; }); @@ -29,7 +28,6 @@ fn bad() { foo(1); foo(2); }); - foo3({}, 2, 2); let b = Bar; b.bar({ 1; diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 145b3c62b..56f6a855d 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,27 +1,12 @@ error: passing a unit value to a function --> $DIR/unit_arg.rs:23:5 | -LL | foo({}); - | ^^^^^^^ - | - = note: `-D clippy::unit-arg` implied by `-D warnings` -help: move the expression in front of the call... - | -LL | {}; - | -help: ...and use a unit literal instead - | -LL | foo(()); - | ^^ - -error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:5 - | LL | / foo({ LL | | 1; LL | | }); | |______^ | + = note: `-D clippy::unit-arg` implied by `-D warnings` help: remove the semicolon from the last statement in the block | LL | 1 @@ -38,7 +23,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:27:5 + --> $DIR/unit_arg.rs:26:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -53,7 +38,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:5 + --> $DIR/unit_arg.rs:27:5 | LL | / foo({ LL | | foo(1); @@ -80,21 +65,6 @@ LL | foo(()); error: passing a unit value to a function --> $DIR/unit_arg.rs:32:5 | -LL | foo3({}, 2, 2); - | ^^^^^^^^^^^^^^ - | -help: move the expression in front of the call... - | -LL | {}; - | -help: ...and use a unit literal instead - | -LL | foo3((), 2, 2); - | ^^ - -error: passing a unit value to a function - --> $DIR/unit_arg.rs:34:5 - | LL | / b.bar({ LL | | 1; LL | | }); @@ -116,7 +86,7 @@ LL | b.bar(()); | ^^ error: passing unit values to a function - --> $DIR/unit_arg.rs:37:5 + --> $DIR/unit_arg.rs:35:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +102,7 @@ LL | taking_multiple_units((), ()); | ^^ ^^ error: passing unit values to a function - --> $DIR/unit_arg.rs:38:5 + --> $DIR/unit_arg.rs:36:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -158,7 +128,7 @@ LL | taking_multiple_units((), ()); | ^^ ^^ error: passing unit values to a function - --> $DIR/unit_arg.rs:42:5 + --> $DIR/unit_arg.rs:40:5 | LL | / taking_multiple_units( LL | | { @@ -193,7 +163,7 @@ LL | (), | error: passing a unit value to a function - --> $DIR/unit_arg.rs:84:5 + --> $DIR/unit_arg.rs:82:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ @@ -207,5 +177,5 @@ help: ...and use a unit literal instead LL | Some(()) | ^^ -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs new file mode 100644 index 000000000..18a31eb3d --- /dev/null +++ b/tests/ui/unit_arg_empty_blocks.rs @@ -0,0 +1,26 @@ +#![warn(clippy::unit_arg)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] + +use std::fmt::Debug; + +fn foo(t: T) { + println!("{:?}", t); +} + +fn foo3(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo({}); + foo3({}, 2, 2); + taking_two_units({}, foo(0)); + taking_three_units({}, foo(0), foo(1)); +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr new file mode 100644 index 000000000..bb5848358 --- /dev/null +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -0,0 +1,51 @@ +error: passing a unit value to a function + --> $DIR/unit_arg_empty_blocks.rs:15:5 + | +LL | foo({}); + | ^^^^--^ + | | + | help: use a unit literal instead: `()` + | + = note: `-D clippy::unit-arg` implied by `-D warnings` + +error: passing a unit value to a function + --> $DIR/unit_arg_empty_blocks.rs:16:5 + | +LL | foo3({}, 2, 2); + | ^^^^^--^^^^^^^ + | | + | help: use a unit literal instead: `()` + +error: passing unit values to a function + --> $DIR/unit_arg_empty_blocks.rs:17:5 + | +LL | taking_two_units({}, foo(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call... + | +LL | foo(0); + | +help: ...and use unit literals instead + | +LL | taking_two_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg_empty_blocks.rs:18:5 + | +LL | taking_three_units({}, foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(0); +LL | foo(1); + | +help: ...and use unit literals instead + | +LL | taking_three_units((), (), ()); + | ^^ ^^ ^^ + +error: aborting due to 4 previous errors +