Implement let_underscore_future

This commit is contained in:
Steven Casper 2022-10-31 12:50:59 -07:00
parent 37d338c1ef
commit 6dcade0692
3 changed files with 83 additions and 2 deletions

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{is_must_use_ty, match_type};
use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
use clippy_utils::{is_must_use_func_call, paths};
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
@ -59,7 +59,31 @@ declare_clippy_lint! {
"non-binding let on a synchronization lock"
}
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]);
declare_clippy_lint! {
/// ### What it does
/// Checks for `let _ = <expr>` where the resulting type of expr implements `Future`
///
/// ### Why is this bad?
/// Futures must be polled for work to be done. The original intention was most likely to await the future
/// and ignore the resulting value.
///
/// ### Example
/// ```rust,ignore
/// async fn foo() -> Result<(), ()> { }
/// let _ = foo();
/// ```
///
/// Use instead:
/// ```rust,ignore
/// let _ = foo().await;
/// ```
#[clippy::version = "1.66"]
pub LET_UNDERSCORE_FUTURE,
suspicious,
"non-binding let on a future"
}
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::PARKING_LOT_MUTEX_GUARD,
@ -88,6 +112,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`",
);
} else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
&& implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) {
span_lint_and_help(
cx,
LET_UNDERSCORE_FUTURE,
local.span,
"non-binding let on a future",
None,
"consider awaiting the future or dropping explicitly with `std::mem::drop`"
);
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,

View File

@ -0,0 +1,20 @@
use std::future::Future;
async fn some_async_fn() {}
fn sync_side_effects() {}
fn custom() -> impl Future<Output = ()> {
sync_side_effects();
async {}
}
fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
fn main() {
let _ = some_async_fn();
let _ = custom();
let mut future = some_async_fn();
do_something_to_future(&mut future);
let _ = future;
}

View File

@ -0,0 +1,27 @@
error: non-binding let on a future
--> $DIR/let_underscore_future.rs:14:5
|
LL | let _ = some_async_fn();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
= note: `-D clippy::let-underscore-future` implied by `-D warnings`
error: non-binding let on a future
--> $DIR/let_underscore_future.rs:15:5
|
LL | let _ = custom();
| ^^^^^^^^^^^^^^^^^
|
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
error: non-binding let on a future
--> $DIR/let_underscore_future.rs:19:5
|
LL | let _ = future;
| ^^^^^^^^^^^^^^^
|
= help: consider awaiting the future or dropping explicitly with `std::mem::drop`
error: aborting due to 3 previous errors