Skip to content

Commit ce33d93

Browse files
committed
fix: async_yields_async missing parens
1 parent 2b9df36 commit ce33d93

File tree

6 files changed

+87
-21
lines changed

6 files changed

+87
-21
lines changed

clippy_lints/src/async_yields_async.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_hir_and_then;
2-
use clippy_utils::source::{snippet, walk_span_to_context};
2+
use clippy_utils::is_expr_async_block;
3+
use clippy_utils::source::walk_span_to_context;
4+
use clippy_utils::sugg::Sugg;
35
use clippy_utils::ty::implements_trait;
46
use rustc_errors::Applicability;
57
use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath};
@@ -87,15 +89,22 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
8789
let expr_ty = typeck_results.expr_ty(body_expr);
8890

8991
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
90-
let return_expr_span = match &body_expr.kind {
92+
let return_expr = match &body_expr.kind {
9193
// XXXkhuey there has to be a better way.
92-
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
93-
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
94+
ExprKind::Block(block, _) => block.expr.map(|e| (e, e.span)),
95+
ExprKind::Path(QPath::Resolved(_, path)) => Some((body_expr, path.span)),
9496
_ => None,
9597
};
96-
if let Some(return_expr_span) = return_expr_span {
98+
if let Some((return_expr, return_expr_span)) = return_expr {
9799
let return_expr_span =
98100
walk_span_to_context(return_expr_span, expr.span.ctxt()).unwrap_or(return_expr_span);
101+
let mut applicability = Applicability::MaybeIncorrect;
102+
let mut return_expr_snip =
103+
Sugg::hir_with_context(cx, return_expr, expr.span.ctxt(), "..", &mut applicability);
104+
if !is_expr_async_block(return_expr) {
105+
return_expr_snip = return_expr_snip.maybe_paren();
106+
}
107+
99108
span_lint_hir_and_then(
100109
cx,
101110
ASYNC_YIELDS_ASYNC,
@@ -108,8 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
108117
db.span_suggestion(
109118
return_expr_span,
110119
"consider awaiting this value",
111-
format!("{}.await", snippet(cx, return_expr_span, "..")),
112-
Applicability::MaybeIncorrect,
120+
format!("{}.await", return_expr_snip),
121+
applicability,
113122
);
114123
},
115124
);

clippy_lints/src/unused_async.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use clippy_utils::diagnostics::span_lint_hir_and_then;
2-
use clippy_utils::is_def_id_trait_method;
32
use clippy_utils::usage::is_todo_unimplemented_stub;
3+
use clippy_utils::{is_def_id_trait_method, is_expr_async_block};
44
use rustc_hir::def::DefKind;
55
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
66
use rustc_hir::{
7-
Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Defaultness, Expr, ExprKind, FnDecl, HirId, Node,
8-
TraitItem, YieldSource,
7+
Body, ClosureKind, CoroutineDesugaring, CoroutineKind, Defaultness, Expr, ExprKind, FnDecl, HirId, Node, TraitItem,
8+
YieldSource,
99
};
1010
use rustc_lint::{LateContext, LateLintPass};
1111
use rustc_middle::hir::nested_filter;
@@ -83,13 +83,7 @@ impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> {
8383
}
8484
}
8585

86-
let is_async_block = matches!(
87-
ex.kind,
88-
ExprKind::Closure(Closure {
89-
kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
90-
..
91-
})
92-
);
86+
let is_async_block = is_expr_async_block(ex);
9387

9488
if is_async_block {
9589
self.async_depth += 1;

clippy_utils/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3632,3 +3632,14 @@ pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>)
36323632
)
36333633
})
36343634
}
3635+
3636+
/// Checks if the expression is an async block (i.e., `async { ... }`).
3637+
pub fn is_expr_async_block(expr: &Expr<'_>) -> bool {
3638+
matches!(
3639+
expr.kind,
3640+
ExprKind::Closure(Closure {
3641+
kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
3642+
..
3643+
})
3644+
)
3645+
}

tests/ui/async_yields_async.fixed

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ fn check_expect_suppression() {
8181
};
8282
}
8383

84+
#[allow(clippy::let_underscore_future)]
8485
fn issue15552() {
8586
async fn bar(i: i32) {}
8687

@@ -97,4 +98,24 @@ fn issue15552() {
9798
let y = async { call_bar!().await };
9899
//~^ async_yields_async
99100
//~| async_yields_async
101+
102+
use std::future::{Future, Ready};
103+
use std::ops::Add;
104+
use std::pin::Pin;
105+
use std::task::{Context, Poll};
106+
struct CustomFutureType;
107+
impl Add for CustomFutureType {
108+
type Output = Self;
109+
fn add(self, other: Self) -> Self {
110+
self
111+
}
112+
}
113+
impl Future for CustomFutureType {
114+
type Output = ();
115+
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
116+
Poll::Ready(())
117+
}
118+
}
119+
let _ = async { (CustomFutureType + CustomFutureType).await };
120+
//~^ async_yields_async
100121
}

tests/ui/async_yields_async.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ fn check_expect_suppression() {
8181
};
8282
}
8383

84+
#[allow(clippy::let_underscore_future)]
8485
fn issue15552() {
8586
async fn bar(i: i32) {}
8687

@@ -97,4 +98,24 @@ fn issue15552() {
9798
let y = async { call_bar!() };
9899
//~^ async_yields_async
99100
//~| async_yields_async
101+
102+
use std::future::{Future, Ready};
103+
use std::ops::Add;
104+
use std::pin::Pin;
105+
use std::task::{Context, Poll};
106+
struct CustomFutureType;
107+
impl Add for CustomFutureType {
108+
type Output = Self;
109+
fn add(self, other: Self) -> Self {
110+
self
111+
}
112+
}
113+
impl Future for CustomFutureType {
114+
type Output = ();
115+
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
116+
Poll::Ready(())
117+
}
118+
}
119+
let _ = async { CustomFutureType + CustomFutureType };
120+
//~^ async_yields_async
100121
}

tests/ui/async_yields_async.stderr

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ LL | | };
9090
| |_____- outer async construct
9191

9292
error: an async construct yields a type which is itself awaitable
93-
--> tests/ui/async_yields_async.rs:95:21
93+
--> tests/ui/async_yields_async.rs:96:21
9494
|
9595
LL | let x = async { call_bar!(5) };
9696
| --^^^^^^^^^^^^--
@@ -100,7 +100,7 @@ LL | let x = async { call_bar!(5) };
100100
| outer async construct
101101

102102
error: an async construct yields a type which is itself awaitable
103-
--> tests/ui/async_yields_async.rs:97:21
103+
--> tests/ui/async_yields_async.rs:98:21
104104
|
105105
LL | let y = async { call_bar!() };
106106
| --^^^^^^^^^^^--
@@ -110,7 +110,7 @@ LL | let y = async { call_bar!() };
110110
| outer async construct
111111

112112
error: an async construct yields a type which is itself awaitable
113-
--> tests/ui/async_yields_async.rs:89:21
113+
--> tests/ui/async_yields_async.rs:90:21
114114
|
115115
LL | async { bar(5) }
116116
| --^^^^^^--
@@ -124,5 +124,15 @@ LL | let y = async { call_bar!() };
124124
|
125125
= note: this error originates in the macro `call_bar` (in Nightly builds, run with -Z macro-backtrace for more info)
126126

127-
error: aborting due to 9 previous errors
127+
error: an async construct yields a type which is itself awaitable
128+
--> tests/ui/async_yields_async.rs:119:21
129+
|
130+
LL | let _ = async { CustomFutureType + CustomFutureType };
131+
| --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--
132+
| | |
133+
| | awaitable value not awaited
134+
| | help: consider awaiting this value: `(CustomFutureType + CustomFutureType).await`
135+
| outer async construct
136+
137+
error: aborting due to 10 previous errors
128138

0 commit comments

Comments
 (0)