diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 3c77db84a405..9f3b0957eab1 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let Some(vis_snip) = vis_span.get_source_text(cx) && let Some(header_snip) = header_span.get_source_text(cx) && let Some(ret_pos) = position_before_rarrow(&header_snip) - && let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output) + && let Some((_, ret_snip)) = suggested_ret(cx, output) { let header_snip = if vis_snip.is_empty() { format!("async {}", &header_snip[..ret_pos]) @@ -82,19 +82,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) }; - let help = format!("make the function `async` and {ret_sugg}"); - diag.span_suggestion( - header_span, - help, - format!("{header_snip}{ret_snip}"), - Applicability::MachineApplicable, - ); + let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)).to_string(); - let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)); - diag.span_suggestion( - block.span, - "move the body of the async block to the enclosing function", - body_snip, + diag.multipart_suggestion( + "make the function `async` and return the output of the future directly", + vec![ + (header_span, format!("{header_snip}{ret_snip}")), + (block.span, body_snip), + ], Applicability::MachineApplicable, ); } diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed new file mode 100644 index 000000000000..dc1cb8e11fca --- /dev/null +++ b/tests/ui/manual_async_fn.fixed @@ -0,0 +1,116 @@ +#![warn(clippy::manual_async_fn)] +#![allow(clippy::needless_pub_self, unused)] + +use std::future::Future; + +async fn fut() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut2() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut3() -> i32 { 42 } + +async fn empty_fut() {} + +#[rustfmt::skip] +async fn empty_fut2() {} + +#[rustfmt::skip] +async fn empty_fut3() {} + +async fn core_fut() -> i32 { 42 } + +// should be ignored +fn has_other_stmts() -> impl core::future::Future { + let _ = 42; + async move { 42 } +} + +// should be ignored +fn not_fut() -> i32 { + 42 +} + +// should be ignored +async fn already_async() -> impl Future { + async { 42 } +} + +struct S; +impl S { + async fn inh_fut() -> i32 { + // NOTE: this code is here just to check that the indentation is correct in the suggested fix + let a = 42; + let b = 21; + if a < b { + let c = 21; + let d = 42; + if c < d { + let _ = 42; + } + } + 42 + } + + // should be ignored + fn not_fut(&self) -> i32 { + 42 + } + + // should be ignored + fn has_other_stmts() -> impl core::future::Future { + let _ = 42; + async move { 42 } + } + + // should be ignored + async fn already_async(&self) -> impl Future { + async { 42 } + } +} + +// Tests related to lifetime capture + +async fn elided(_: &i32) -> i32 { 42 } + +// should be ignored +fn elided_not_bound(_: &i32) -> impl Future { + async { 42 } +} + +#[allow(clippy::needless_lifetimes)] +async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } + +// should be ignored +#[allow(clippy::needless_lifetimes)] +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future { + async { 42 } +} + +// should be ignored +mod issue_5765 { + use std::future::Future; + + struct A; + impl A { + fn f(&self) -> impl Future { + async {} + } + } + + fn test() { + let _future = { + let a = A; + a.f() + }; + } +} + +pub async fn issue_10450() -> i32 { 42 } + +pub(crate) async fn issue_10450_2() -> i32 { 42 } + +pub(self) async fn issue_10450_3() -> i32 { 42 } + +fn main() {} diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index 6b8ac5033a92..9ca7654a3688 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,8 +1,6 @@ #![warn(clippy::manual_async_fn)] #![allow(clippy::needless_pub_self, unused)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::future::Future; fn fut() -> impl Future { @@ -99,6 +97,7 @@ fn elided_not_bound(_: &i32) -> impl Future { async { 42 } } +#[allow(clippy::needless_lifetimes)] fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { async { 42 } } diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index f88fc30b3b54..68a97243436d 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -1,5 +1,5 @@ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:8:1 + --> tests/ui/manual_async_fn.rs:6:1 | LL | fn fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,116 +8,84 @@ LL | fn fut() -> impl Future { = help: to override `-D warnings` add `#[allow(clippy::manual_async_fn)]` help: make the function `async` and return the output of the future directly | -LL | async fn fut() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn fut() -> impl Future { 42 } - | ~~~~~~ +LL | async fn fut() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:13:1 + --> tests/ui/manual_async_fn.rs:11:1 | LL | fn fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn fut2() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn fut2() ->impl Future { 42 } - | ~~~~~~ +LL | async fn fut2() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:18:1 + --> tests/ui/manual_async_fn.rs:16:1 | LL | fn fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn fut3() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn fut3()-> impl Future { 42 } - | ~~~~~~ +LL | async fn fut3() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:22:1 + --> tests/ui/manual_async_fn.rs:20:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: make the function `async` and remove the return type - | -LL | async fn empty_fut() { - | ~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function +help: make the function `async` and return the output of the future directly | -LL | fn empty_fut() -> impl Future {} - | ~~ +LL | async fn empty_fut() {} + | ~~~~~~~~~~~~~~~~~~~~ ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:27:1 + --> tests/ui/manual_async_fn.rs:25:1 | LL | fn empty_fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: make the function `async` and remove the return type - | -LL | async fn empty_fut2() { - | ~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function +help: make the function `async` and return the output of the future directly | -LL | fn empty_fut2() ->impl Future {} - | ~~ +LL | async fn empty_fut2() {} + | ~~~~~~~~~~~~~~~~~~~~~ ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:32:1 + --> tests/ui/manual_async_fn.rs:30:1 | LL | fn empty_fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: make the function `async` and remove the return type - | -LL | async fn empty_fut3() { - | ~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function +help: make the function `async` and return the output of the future directly | -LL | fn empty_fut3()-> impl Future {} - | ~~ +LL | async fn empty_fut3() {} + | ~~~~~~~~~~~~~~~~~~~~~ ~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:36:1 + --> tests/ui/manual_async_fn.rs:34:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn core_fut() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn core_fut() -> impl core::future::Future { 42 } - | ~~~~~~ +LL | async fn core_fut() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:58:5 + --> tests/ui/manual_async_fn.rs:56:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn inh_fut() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL ~ fn inh_fut() -> impl Future { +LL ~ async fn inh_fut() -> i32 { LL + // NOTE: this code is here just to check that the indentation is correct in the suggested fix LL + let a = 42; LL + let b = 21; @@ -133,79 +101,59 @@ LL + } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:93:1 + --> tests/ui/manual_async_fn.rs:91:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn elided(_: &i32) -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn elided(_: &i32) -> impl Future + '_ { 42 } - | ~~~~~~ +LL | async fn elided(_: &i32) -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:102:1 + --> tests/ui/manual_async_fn.rs:101:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } - | ~~~~~~ +LL | async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:131:1 + --> tests/ui/manual_async_fn.rs:130:1 | LL | pub fn issue_10450() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | pub async fn issue_10450() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | pub fn issue_10450() -> impl Future { 42 } - | ~~~~~~ +LL | pub async fn issue_10450() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:135:1 + --> tests/ui/manual_async_fn.rs:134:1 | LL | pub(crate) fn issue_10450_2() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | pub(crate) async fn issue_10450_2() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | pub(crate) fn issue_10450_2() -> impl Future { 42 } - | ~~~~~~ +LL | pub(crate) async fn issue_10450_2() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:139:1 + --> tests/ui/manual_async_fn.rs:138:1 | LL | pub(self) fn issue_10450_3() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and return the output of the future directly | -LL | pub(self) async fn issue_10450_3() -> i32 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: move the body of the async block to the enclosing function - | -LL | pub(self) fn issue_10450_3() -> impl Future { 42 } - | ~~~~~~ +LL | pub(self) async fn issue_10450_3() -> i32 { 42 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ error: aborting due to 13 previous errors