|
1 | 1 | 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; |
3 | 5 | use clippy_utils::ty::implements_trait; |
4 | 6 | use rustc_errors::Applicability; |
5 | | -use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath}; |
| 7 | +use rustc_hir::{ |
| 8 | + Block, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath, |
| 9 | +}; |
6 | 10 | use rustc_lint::{LateContext, LateLintPass}; |
7 | 11 | use rustc_session::declare_lint_pass; |
8 | 12 |
|
@@ -87,31 +91,37 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { |
87 | 91 | let expr_ty = typeck_results.expr_ty(body_expr); |
88 | 92 |
|
89 | 93 | if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { |
90 | | - let return_expr_span = match &body_expr.kind { |
91 | | - // 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 | | - _ => None, |
| 94 | + let (return_expr, return_expr_span) = match &body_expr.kind { |
| 95 | + ExprKind::Block(Block { expr: Some(e), .. }, _) => (*e, e.span), |
| 96 | + ExprKind::Path(QPath::Resolved(_, path)) => (body_expr, path.span), |
| 97 | + _ => return, |
95 | 98 | }; |
96 | | - if let Some(return_expr_span) = return_expr_span { |
97 | | - span_lint_hir_and_then( |
98 | | - cx, |
99 | | - ASYNC_YIELDS_ASYNC, |
100 | | - body_expr.hir_id, |
101 | | - return_expr_span, |
102 | | - "an async construct yields a type which is itself awaitable", |
103 | | - |db| { |
104 | | - db.span_label(body_expr.span, "outer async construct"); |
105 | | - db.span_label(return_expr_span, "awaitable value not awaited"); |
106 | | - db.span_suggestion( |
107 | | - return_expr_span, |
108 | | - "consider awaiting this value", |
109 | | - format!("{}.await", snippet(cx, return_expr_span, "..")), |
110 | | - Applicability::MaybeIncorrect, |
111 | | - ); |
112 | | - }, |
113 | | - ); |
| 99 | + |
| 100 | + let return_expr_span = 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(); |
114 | 106 | } |
| 107 | + |
| 108 | + span_lint_hir_and_then( |
| 109 | + cx, |
| 110 | + ASYNC_YIELDS_ASYNC, |
| 111 | + body_expr.hir_id, |
| 112 | + return_expr_span, |
| 113 | + "an async construct yields a type which is itself awaitable", |
| 114 | + |db| { |
| 115 | + db.span_label(body_expr.span, "outer async construct"); |
| 116 | + db.span_label(return_expr_span, "awaitable value not awaited"); |
| 117 | + db.span_suggestion( |
| 118 | + return_expr_span, |
| 119 | + "consider awaiting this value", |
| 120 | + format!("{return_expr_snip}.await"), |
| 121 | + applicability, |
| 122 | + ); |
| 123 | + }, |
| 124 | + ); |
115 | 125 | } |
116 | 126 | } |
117 | 127 | } |
0 commit comments