mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 21:15:18 +03:00
fix: async_yields_async wrongly unmangled macros
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::is_expr_async_block;
|
||||
use clippy_utils::source::walk_span_to_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath};
|
||||
use rustc_hir::{
|
||||
Block, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
@@ -87,31 +91,37 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
let expr_ty = typeck_results.expr_ty(body_expr);
|
||||
|
||||
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
|
||||
let return_expr_span = match &body_expr.kind {
|
||||
// XXXkhuey there has to be a better way.
|
||||
ExprKind::Block(block, _) => block.expr.map(|e| e.span),
|
||||
ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
|
||||
_ => None,
|
||||
let (return_expr, return_expr_span) = match &body_expr.kind {
|
||||
ExprKind::Block(Block { expr: Some(e), .. }, _) => (*e, e.span),
|
||||
ExprKind::Path(QPath::Resolved(_, path)) => (body_expr, path.span),
|
||||
_ => return,
|
||||
};
|
||||
if let Some(return_expr_span) = return_expr_span {
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
ASYNC_YIELDS_ASYNC,
|
||||
body_expr.hir_id,
|
||||
return_expr_span,
|
||||
"an async construct yields a type which is itself awaitable",
|
||||
|db| {
|
||||
db.span_label(body_expr.span, "outer async construct");
|
||||
db.span_label(return_expr_span, "awaitable value not awaited");
|
||||
db.span_suggestion(
|
||||
return_expr_span,
|
||||
"consider awaiting this value",
|
||||
format!("{}.await", snippet(cx, return_expr_span, "..")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
let return_expr_span = walk_span_to_context(return_expr_span, expr.span.ctxt()).unwrap_or(return_expr_span);
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let mut return_expr_snip =
|
||||
Sugg::hir_with_context(cx, return_expr, expr.span.ctxt(), "..", &mut applicability);
|
||||
if !is_expr_async_block(return_expr) {
|
||||
return_expr_snip = return_expr_snip.maybe_paren();
|
||||
}
|
||||
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
ASYNC_YIELDS_ASYNC,
|
||||
body_expr.hir_id,
|
||||
return_expr_span,
|
||||
"an async construct yields a type which is itself awaitable",
|
||||
|db| {
|
||||
db.span_label(body_expr.span, "outer async construct");
|
||||
db.span_label(return_expr_span, "awaitable value not awaited");
|
||||
db.span_suggestion(
|
||||
return_expr_span,
|
||||
"consider awaiting this value",
|
||||
format!("{return_expr_snip}.await"),
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-3
@@ -102,9 +102,9 @@
|
||||
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
||||
use rustc_hir::{
|
||||
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring,
|
||||
CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl,
|
||||
ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
|
||||
Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
|
||||
CoroutineKind, CoroutineSource, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs,
|
||||
HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId,
|
||||
OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
|
||||
TraitItemKind, TraitRef, TyKind, UnOp, def, find_attr,
|
||||
};
|
||||
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
|
||||
@@ -3632,3 +3632,17 @@ pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if the expression is an async block (i.e., `async { ... }`).
|
||||
pub fn is_expr_async_block(expr: &Expr<'_>) -> bool {
|
||||
matches!(
|
||||
expr.kind,
|
||||
ExprKind::Closure(Closure {
|
||||
kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(
|
||||
CoroutineDesugaring::Async,
|
||||
CoroutineSource::Block
|
||||
)),
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,3 +80,42 @@ fn check_expect_suppression() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(clippy::let_underscore_future)]
|
||||
fn issue15552() {
|
||||
async fn bar(i: i32) {}
|
||||
|
||||
macro_rules! call_bar {
|
||||
() => {
|
||||
async { bar(5).await }
|
||||
};
|
||||
($e:expr) => {
|
||||
bar($e)
|
||||
};
|
||||
}
|
||||
let x = async { call_bar!(5).await };
|
||||
//~^ async_yields_async
|
||||
let y = async { call_bar!().await };
|
||||
//~^ async_yields_async
|
||||
//~| async_yields_async
|
||||
|
||||
use std::future::{Future, Ready};
|
||||
use std::ops::Add;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
struct CustomFutureType;
|
||||
impl Add for CustomFutureType {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl Future for CustomFutureType {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
let _ = async { (CustomFutureType + CustomFutureType).await };
|
||||
//~^ async_yields_async
|
||||
}
|
||||
|
||||
@@ -80,3 +80,42 @@ fn check_expect_suppression() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(clippy::let_underscore_future)]
|
||||
fn issue15552() {
|
||||
async fn bar(i: i32) {}
|
||||
|
||||
macro_rules! call_bar {
|
||||
() => {
|
||||
async { bar(5) }
|
||||
};
|
||||
($e:expr) => {
|
||||
bar($e)
|
||||
};
|
||||
}
|
||||
let x = async { call_bar!(5) };
|
||||
//~^ async_yields_async
|
||||
let y = async { call_bar!() };
|
||||
//~^ async_yields_async
|
||||
//~| async_yields_async
|
||||
|
||||
use std::future::{Future, Ready};
|
||||
use std::ops::Add;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
struct CustomFutureType;
|
||||
impl Add for CustomFutureType {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl Future for CustomFutureType {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
let _ = async { CustomFutureType + CustomFutureType };
|
||||
//~^ async_yields_async
|
||||
}
|
||||
|
||||
@@ -89,5 +89,50 @@ LL | | CustomFutureType
|
||||
LL | | };
|
||||
| |_____- outer async construct
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:96:21
|
||||
|
|
||||
LL | let x = async { call_bar!(5) };
|
||||
| --^^^^^^^^^^^^--
|
||||
| | |
|
||||
| | awaitable value not awaited
|
||||
| | help: consider awaiting this value: `call_bar!(5).await`
|
||||
| outer async construct
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:98:21
|
||||
|
|
||||
LL | let y = async { call_bar!() };
|
||||
| --^^^^^^^^^^^--
|
||||
| | |
|
||||
| | awaitable value not awaited
|
||||
| | help: consider awaiting this value: `call_bar!().await`
|
||||
| outer async construct
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:90:21
|
||||
|
|
||||
LL | async { bar(5) }
|
||||
| --^^^^^^--
|
||||
| | |
|
||||
| | awaitable value not awaited
|
||||
| | help: consider awaiting this value: `bar(5).await`
|
||||
| outer async construct
|
||||
...
|
||||
LL | let y = async { call_bar!() };
|
||||
| ----------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `call_bar` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> tests/ui/async_yields_async.rs:119:21
|
||||
|
|
||||
LL | let _ = async { CustomFutureType + CustomFutureType };
|
||||
| --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--
|
||||
| | |
|
||||
| | awaitable value not awaited
|
||||
| | help: consider awaiting this value: `(CustomFutureType + CustomFutureType).await`
|
||||
| outer async construct
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
||||
Reference in New Issue
Block a user