]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/async_yields_async.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / async_yields_async.rs
CommitLineData
f20569fa
XL
1use crate::utils::{implements_trait, snippet, span_lint_and_then};
2use rustc_errors::Applicability;
3use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath};
4use rustc_lint::{LateContext, LateLintPass};
5use rustc_session::{declare_lint_pass, declare_tool_lint};
6
7declare_clippy_lint! {
8 /// **What it does:** Checks for async blocks that yield values of types
9 /// that can themselves be awaited.
10 ///
11 /// **Why is this bad?** An await is likely missing.
12 ///
13 /// **Known problems:** None.
14 ///
15 /// **Example:**
16 ///
17 /// ```rust
18 /// async fn foo() {}
19 ///
20 /// fn bar() {
21 /// let x = async {
22 /// foo()
23 /// };
24 /// }
25 /// ```
26 /// Use instead:
27 /// ```rust
28 /// async fn foo() {}
29 ///
30 /// fn bar() {
31 /// let x = async {
32 /// foo().await
33 /// };
34 /// }
35 /// ```
36 pub ASYNC_YIELDS_ASYNC,
37 correctness,
38 "async blocks that return a type that can be awaited"
39}
40
41declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
42
43impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
44 fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
45 use AsyncGeneratorKind::{Block, Closure};
46 // For functions, with explicitly defined types, don't warn.
47 // XXXkhuey maybe we should?
48 if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind {
49 if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
50 let body_id = BodyId {
51 hir_id: body.value.hir_id,
52 };
53 let typeck_results = cx.tcx.typeck_body(body_id);
54 let expr_ty = typeck_results.expr_ty(&body.value);
55
56 if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
57 let return_expr_span = match &body.value.kind {
58 // XXXkhuey there has to be a better way.
59 ExprKind::Block(block, _) => block.expr.map(|e| e.span),
60 ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
61 _ => None,
62 };
63 if let Some(return_expr_span) = return_expr_span {
64 span_lint_and_then(
65 cx,
66 ASYNC_YIELDS_ASYNC,
67 return_expr_span,
68 "an async construct yields a type which is itself awaitable",
69 |db| {
70 db.span_label(body.value.span, "outer async construct");
71 db.span_label(return_expr_span, "awaitable value not awaited");
72 db.span_suggestion(
73 return_expr_span,
74 "consider awaiting this value",
75 format!("{}.await", snippet(cx, return_expr_span, "..")),
76 Applicability::MaybeIncorrect,
77 );
78 },
79 );
80 }
81 }
82 }
83 }
84 }
85}