|
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