Skip to content

[redundant_closure_call]: avoid duplicated async keyword when triggering on closure that returns async block #11363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions clippy_lints/src/redundant_closure_call.rs
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@ use clippy_utils::get_parent_expr;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit as hir_visit;
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
@@ -60,11 +60,14 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
}
}

/// Checks if the body is owned by an async closure
fn is_async_closure(body: &hir::Body<'_>) -> bool {
if let hir::ExprKind::Closure(closure) = body.value.kind
&& let [resume_ty] = closure.fn_decl.inputs
&& let hir::TyKind::Path(hir::QPath::LangItem(hir::LangItem::ResumeTy, ..)) = resume_ty.kind
/// Checks if the body is owned by an async closure.
/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
/// }`.
fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool {
if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
&& let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body)
// checks whether it is `async || whatever_expression`
&& let Some(CoroutineKind::Async(CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind
{
true
} else {
@@ -100,7 +103,7 @@ fn find_innermost_closure<'tcx>(
data = Some((
body.value,
closure.fn_decl,
if is_async_closure(body) {
if is_async_closure(cx, body) {
ty::Asyncness::Yes
} else {
ty::Asyncness::No
@@ -173,12 +176,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
hint = hint.asyncify();
}

diag.span_suggestion(
full_expr.span,
"try doing something like",
hint.maybe_par(),
applicability,
);
let is_in_fn_call_arg =
clippy_utils::get_parent_node(cx.tcx, expr.hir_id).is_some_and(|x| match x {
Node::Expr(expr) => matches!(expr.kind, hir::ExprKind::Call(_, _)),
_ => false,
});

// avoid clippy::double_parens
if !is_in_fn_call_arg {
hint = hint.maybe_par();
};

diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability);
}
},
);
18 changes: 18 additions & 0 deletions tests/ui/redundant_closure_call_fixable.fixed
Original file line number Diff line number Diff line change
@@ -84,3 +84,21 @@ fn issue9956() {
bar()(42, 5);
foo(42, 5);
}

async fn issue11357() {
async {}.await;
}

mod issue11707 {
use core::future::Future;

fn spawn_on(fut: impl Future<Output = ()>) {}

fn demo() {
spawn_on(async move {});
}
}

fn avoid_double_parens() {
std::convert::identity(13_i32 + 36_i32).leading_zeros();
}
18 changes: 18 additions & 0 deletions tests/ui/redundant_closure_call_fixable.rs
Original file line number Diff line number Diff line change
@@ -84,3 +84,21 @@ fn issue9956() {
bar()((|| || 42)()(), 5);
foo((|| || 42)()(), 5);
}

async fn issue11357() {
(|| async {})().await;
}

mod issue11707 {
use core::future::Future;

fn spawn_on(fut: impl Future<Output = ()>) {}

fn demo() {
spawn_on((|| async move {})());
}
}

fn avoid_double_parens() {
std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros();
}
20 changes: 19 additions & 1 deletion tests/ui/redundant_closure_call_fixable.stderr
Original file line number Diff line number Diff line change
@@ -123,5 +123,23 @@ error: try not to call a closure in the expression where it is declared
LL | foo((|| || 42)()(), 5);
| ^^^^^^^^^^^^^^ help: try doing something like: `42`

error: aborting due to 14 previous errors
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:89:5
|
LL | (|| async {})().await;
| ^^^^^^^^^^^^^^^ help: try doing something like: `async {}`

error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:98:18
|
LL | spawn_on((|| async move {})());
| ^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move {}`

error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:103:28
|
LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32`

error: aborting due to 17 previous errors