diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f5a93cebab8..74eea6de4bb 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; @@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall { if_chain! { if let ast::ExprKind::Call(ref paren, _) = expr.kind; if let ast::ExprKind::Paren(ref closure) = paren.kind; - if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind; + if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind; then { let mut visitor = ReturnVisitor::new(); visitor.visit_expr(block); @@ -81,10 +81,19 @@ impl EarlyLintPass for RedundantClosureCall { "try not to call a closure in the expression where it is declared", |diag| { if decl.inputs.is_empty() { - let mut app = Applicability::MachineApplicable; - let hint = - snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); - diag.span_suggestion(expr.span, "try doing something like", hint, app); + let app = Applicability::MachineApplicable; + let mut hint = Sugg::ast(cx, block, ".."); + + if r#async.is_async() { + // `async x` is a syntax error, so it becomes `async { x }` + if !matches!(block.kind, ast::ExprKind::Block(_, _)) { + hint = hint.blockify(); + } + + hint = hint.asyncify(); + } + + diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app); } }, ); diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index bad291dfc25..081c98e2f3c 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -315,6 +315,12 @@ impl<'a> Sugg<'a> { Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self))) } + /// Convenience method to prefix the expression with the `async` keyword. + /// Can be used after `blockify` to create an async block. + pub fn asyncify(self) -> Sugg<'static> { + Sugg::NonParen(Cow::Owned(format!("async {}", self))) + } + /// Convenience method to create the `..` or `...` /// suggestion. pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> { diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index 0abca6fca06..7cd687c95a0 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = 42; + let b = async { + let x = something().await; + let y = something_else().await; + x * y + }; + let c = { + let x = 21; + let y = 2; + x * y + }; + let d = async { something().await }; } diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index f8b9d37a5cc..37e4d223864 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = (|| 42)(); + let b = (async || { + let x = something().await; + let y = something_else().await; + x * y + })(); + let c = (|| { + let x = 21; + let y = 2; + x * y + })(); + let d = (async || something().await)(); } diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index afd704ef12a..56a8e57c0c3 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,10 +1,56 @@ error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:7:13 + --> $DIR/redundant_closure_call_fixable.rs:16:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: aborting due to previous error +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:17:13 + | +LL | let b = (async || { + | _____________^ +LL | | let x = something().await; +LL | | let y = something_else().await; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let b = async { +LL + let x = something().await; +LL + let y = something_else().await; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:22:13 + | +LL | let c = (|| { + | _____________^ +LL | | let x = 21; +LL | | let y = 2; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let c = { +LL + let x = 21; +LL + let y = 2; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:27:13 + | +LL | let d = (async || something().await)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` + +error: aborting due to 4 previous errors