Skip to content

Commit 5ae330f

Browse files
committed
fix: async_yields_async wrongly unmangled macros
1 parent 55286e7 commit 5ae330f

File tree

6 files changed

+157
-18
lines changed

6 files changed

+157
-18
lines changed

clippy_lints/src/async_yields_async.rs

Lines changed: 18 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;
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,13 +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 {
99+
let return_expr_span =
100+
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+
97108
span_lint_hir_and_then(
98109
cx,
99110
ASYNC_YIELDS_ASYNC,
@@ -106,8 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
106117
db.span_suggestion(
107118
return_expr_span,
108119
"consider awaiting this value",
109-
format!("{}.await", snippet(cx, return_expr_span, "..")),
110-
Applicability::MaybeIncorrect,
120+
format!("{return_expr_snip}.await"),
121+
applicability,
111122
);
112123
},
113124
);

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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,42 @@ fn check_expect_suppression() {
8080
}
8181
};
8282
}
83+
84+
#[allow(clippy::let_underscore_future)]
85+
fn issue15552() {
86+
async fn bar(i: i32) {}
87+
88+
macro_rules! call_bar {
89+
() => {
90+
async { bar(5).await }
91+
};
92+
($e:expr) => {
93+
bar($e)
94+
};
95+
}
96+
let x = async { call_bar!(5).await };
97+
//~^ async_yields_async
98+
let y = async { call_bar!().await };
99+
//~^ async_yields_async
100+
//~| 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
121+
}

tests/ui/async_yields_async.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,42 @@ fn check_expect_suppression() {
8080
}
8181
};
8282
}
83+
84+
#[allow(clippy::let_underscore_future)]
85+
fn issue15552() {
86+
async fn bar(i: i32) {}
87+
88+
macro_rules! call_bar {
89+
() => {
90+
async { bar(5) }
91+
};
92+
($e:expr) => {
93+
bar($e)
94+
};
95+
}
96+
let x = async { call_bar!(5) };
97+
//~^ async_yields_async
98+
let y = async { call_bar!() };
99+
//~^ async_yields_async
100+
//~| 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
121+
}

tests/ui/async_yields_async.stderr

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,50 @@ LL | | CustomFutureType
8989
LL | | };
9090
| |_____- outer async construct
9191

92-
error: aborting due to 6 previous errors
92+
error: an async construct yields a type which is itself awaitable
93+
--> tests/ui/async_yields_async.rs:96:21
94+
|
95+
LL | let x = async { call_bar!(5) };
96+
| --^^^^^^^^^^^^--
97+
| | |
98+
| | awaitable value not awaited
99+
| | help: consider awaiting this value: `call_bar!(5).await`
100+
| outer async construct
101+
102+
error: an async construct yields a type which is itself awaitable
103+
--> tests/ui/async_yields_async.rs:98:21
104+
|
105+
LL | let y = async { call_bar!() };
106+
| --^^^^^^^^^^^--
107+
| | |
108+
| | awaitable value not awaited
109+
| | help: consider awaiting this value: `call_bar!().await`
110+
| outer async construct
111+
112+
error: an async construct yields a type which is itself awaitable
113+
--> tests/ui/async_yields_async.rs:90:21
114+
|
115+
LL | async { bar(5) }
116+
| --^^^^^^--
117+
| | |
118+
| | awaitable value not awaited
119+
| | help: consider awaiting this value: `bar(5).await`
120+
| outer async construct
121+
...
122+
LL | let y = async { call_bar!() };
123+
| ----------- in this macro invocation
124+
|
125+
= note: this error originates in the macro `call_bar` (in Nightly builds, run with -Z macro-backtrace for more info)
126+
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
93138

0 commit comments

Comments
 (0)