]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/unused_async.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / unused_async.rs
CommitLineData
17df50a5 1use clippy_utils::diagnostics::span_lint_and_help;
5099ac24 2use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
064997fb 3use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, IsAsync, YieldSource};
17df50a5 4use rustc_lint::{LateContext, LateLintPass};
5099ac24 5use rustc_middle::hir::nested_filter;
17df50a5
XL
6use rustc_session::{declare_lint_pass, declare_tool_lint};
7use rustc_span::Span;
8
9declare_clippy_lint! {
94222f64
XL
10 /// ### What it does
11 /// Checks for functions that are declared `async` but have no `.await`s inside of them.
17df50a5 12 ///
94222f64
XL
13 /// ### Why is this bad?
14 /// Async functions with no async code create overhead, both mentally and computationally.
17df50a5
XL
15 /// Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which
16 /// causes runtime overhead and hassle for the caller.
17 ///
94222f64 18 /// ### Example
17df50a5 19 /// ```rust
17df50a5
XL
20 /// async fn get_random_number() -> i64 {
21 /// 4 // Chosen by fair dice roll. Guaranteed to be random.
22 /// }
23 /// let number_future = get_random_number();
923072b8 24 /// ```
17df50a5 25 ///
923072b8
FG
26 /// Use instead:
27 /// ```rust
17df50a5
XL
28 /// fn get_random_number_improved() -> i64 {
29 /// 4 // Chosen by fair dice roll. Guaranteed to be random.
30 /// }
31 /// let number_future = async { get_random_number_improved() };
32 /// ```
a2a8927a 33 #[clippy::version = "1.54.0"]
17df50a5
XL
34 pub UNUSED_ASYNC,
35 pedantic,
36 "finds async functions with no await statements"
37}
38
39declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
40
41struct AsyncFnVisitor<'a, 'tcx> {
42 cx: &'a LateContext<'tcx>,
43 found_await: bool,
44}
45
46impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
5099ac24 47 type NestedFilter = nested_filter::OnlyBodies;
17df50a5
XL
48
49 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
50 if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind {
51 self.found_await = true;
52 }
53 walk_expr(self, ex);
54 }
55
5099ac24
FG
56 fn nested_visit_map(&mut self) -> Self::Map {
57 self.cx.tcx.hir()
17df50a5
XL
58 }
59}
60
61impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
17df50a5
XL
62 fn check_fn(
63 &mut self,
64 cx: &LateContext<'tcx>,
65 fn_kind: FnKind<'tcx>,
66 fn_decl: &'tcx FnDecl<'tcx>,
67 body: &Body<'tcx>,
68 span: Span,
69 hir_id: HirId,
70 ) {
064997fb
FG
71 if !span.from_expansion() && fn_kind.asyncness() == IsAsync::Async {
72 let mut visitor = AsyncFnVisitor { cx, found_await: false };
f2b60f7d 73 walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id);
064997fb
FG
74 if !visitor.found_await {
75 span_lint_and_help(
76 cx,
77 UNUSED_ASYNC,
78 span,
79 "unused `async` for function with no await statements",
80 None,
81 "consider removing the `async` from this function",
82 );
17df50a5
XL
83 }
84 }
85 }
86}