Skip to content

Commit 897f0e4

Browse files
committed
Auto merge of #13471 - y21:issue13466-fp, r=llogiq
Remove method call receiver special casing in `unused_async` lint Fixes the false positive mentioned in #13466 (comment). The false negative in the OP would be nice to fix too, but I'd rather do that in a separate PR because it's much more involved Before this change, the `unused_async` lint would check if the async fn is also used anywhere and avoid linting if so. The exception is if the async function is immediately called, because the returned future handling can be easily removed (and also if we don't have some exceptions then the lint wouldn't trigger anywhere) *or* if it's a method call receiver. I'm not exactly sure why I implemented that special casing for method call receivers in #11200, but it doesn't make much sense in hindsight imo. Especially given that method calls are essentially equivalent to function calls with the receiver as the first argument, which was the primary motivation for not linting in the first place (async fn passed to another function, like `axum::get(handler)` where handler has to be an async fn). changelog: none
2 parents b367d34 + d24a631 commit 897f0e4

File tree

3 files changed

+28
-15
lines changed

3 files changed

+28
-15
lines changed

clippy_lints/src/unused_async.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
22
use clippy_utils::is_def_id_trait_method;
33
use rustc_hir::def::DefKind;
44
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
5-
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
5+
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource};
66
use rustc_lint::{LateContext, LateLintPass};
77
use rustc_middle::hir::nested_filter;
88
use rustc_session::impl_lint_pass;
@@ -137,17 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
137137
}
138138
}
139139

140-
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
141-
fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
142-
matches!(
143-
node,
144-
Node::Expr(Expr {
145-
kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
146-
..
147-
}) if *span == expected_receiver
148-
)
149-
}
150-
140+
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: HirId) {
151141
// Find paths to local async functions that aren't immediately called.
152142
// E.g. `async fn f() {}; let x = f;`
153143
// Depending on how `x` is used, f's asyncness might be required despite not having any `await`
@@ -156,7 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
156146
&& let Some(local_def_id) = def_id.as_local()
157147
&& cx.tcx.def_kind(def_id) == DefKind::Fn
158148
&& cx.tcx.asyncness(def_id).is_async()
159-
&& !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span)
149+
&& let parent = cx.tcx.parent_hir_node(hir_id)
150+
&& !matches!(
151+
parent,
152+
Node::Expr(Expr {
153+
kind: ExprKind::Call(Expr { span, .. }, _),
154+
..
155+
}) if *span == path.span
156+
)
160157
{
161158
self.async_fns_as_value.insert(local_def_id);
162159
}

tests/ui/unused_async.rs

+16
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@ mod issue9695 {
5555
}
5656
}
5757

58+
mod issue13466 {
59+
use std::future::Future;
60+
61+
struct Wrap<F>(F);
62+
impl<F> From<F> for Wrap<F> {
63+
fn from(f: F) -> Self {
64+
Self(f)
65+
}
66+
}
67+
fn takes_fut<F: Fn() -> Fut, Fut: Future>(_: Wrap<F>) {}
68+
async fn unused_async() {}
69+
fn fp() {
70+
takes_fut(unused_async.into());
71+
}
72+
}
73+
5874
async fn foo() -> i32 {
5975
//~^ ERROR: unused `async` for function with no await statements
6076
4

tests/ui/unused_async.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ LL | async fn f3() {}
2727
= help: consider removing the `async` from this function
2828

2929
error: unused `async` for function with no await statements
30-
--> tests/ui/unused_async.rs:58:1
30+
--> tests/ui/unused_async.rs:74:1
3131
|
3232
LL | / async fn foo() -> i32 {
3333
LL | |
@@ -38,7 +38,7 @@ LL | | }
3838
= help: consider removing the `async` from this function
3939

4040
error: unused `async` for function with no await statements
41-
--> tests/ui/unused_async.rs:70:5
41+
--> tests/ui/unused_async.rs:86:5
4242
|
4343
LL | / async fn unused(&self) -> i32 {
4444
LL | |

0 commit comments

Comments
 (0)