2021-03-25 13:29:11 -05:00
|
|
|
use clippy_utils::diagnostics::span_lint_and_help;
|
2022-11-21 13:34:47 -06:00
|
|
|
use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
|
2021-03-25 13:29:11 -05:00
|
|
|
use clippy_utils::{is_must_use_func_call, paths};
|
2020-04-01 14:18:16 -05:00
|
|
|
use rustc_hir::{Local, PatKind};
|
2020-01-12 00:08:41 -06:00
|
|
|
use rustc_lint::{LateContext, LateLintPass};
|
2020-03-30 04:02:14 -05:00
|
|
|
use rustc_middle::lint::in_external_macro;
|
2020-04-07 14:53:56 -05:00
|
|
|
use rustc_middle::ty::subst::GenericArgKind;
|
2020-01-11 05:37:08 -06:00
|
|
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
2019-11-16 08:55:00 -06:00
|
|
|
|
|
|
|
declare_clippy_lint! {
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### What it does
|
2021-10-21 06:11:36 -05:00
|
|
|
/// Checks for `let _ = <expr>` where expr is `#[must_use]`
|
2019-11-16 08:55:00 -06:00
|
|
|
///
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### Why is this bad?
|
2021-10-21 06:11:36 -05:00
|
|
|
/// It's better to explicitly handle the value of a `#[must_use]`
|
|
|
|
/// expr
|
2019-11-16 08:55:00 -06:00
|
|
|
///
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### Example
|
2019-11-16 08:55:00 -06:00
|
|
|
/// ```rust
|
|
|
|
/// fn f() -> Result<u32, u32> {
|
|
|
|
/// Ok(0)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// let _ = f();
|
|
|
|
/// // is_ok() is marked #[must_use]
|
|
|
|
/// let _ = f().is_ok();
|
|
|
|
/// ```
|
2021-12-06 05:33:31 -06:00
|
|
|
#[clippy::version = "1.42.0"]
|
2019-11-16 08:55:00 -06:00
|
|
|
pub LET_UNDERSCORE_MUST_USE,
|
|
|
|
restriction,
|
2022-11-21 13:34:47 -06:00
|
|
|
"non-binding `let` on a `#[must_use]` expression"
|
2019-11-16 08:55:00 -06:00
|
|
|
}
|
|
|
|
|
2020-01-27 08:34:30 -06:00
|
|
|
declare_clippy_lint! {
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### What it does
|
2022-11-21 13:34:47 -06:00
|
|
|
/// Checks for `let _ = sync_lock`. This supports `mutex` and `rwlock` in
|
|
|
|
/// `parking_lot`. For `std` locks see the `rustc` lint
|
|
|
|
/// [`let_underscore_lock`](https://doc.rust-lang.org/nightly/rustc/lints/listing/deny-by-default.html#let-underscore-lock)
|
2020-01-27 08:34:30 -06:00
|
|
|
///
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### Why is this bad?
|
|
|
|
/// This statement immediately drops the lock instead of
|
2020-06-23 10:05:22 -05:00
|
|
|
/// extending its lifetime to the end of the scope, which is often not intended.
|
2020-01-30 09:10:19 -06:00
|
|
|
/// To extend lock lifetime to the end of the scope, use an underscore-prefixed
|
|
|
|
/// name instead (i.e. _lock). If you want to explicitly drop the lock,
|
|
|
|
/// `std::mem::drop` conveys your intention better and is less error-prone.
|
2020-01-27 08:34:30 -06:00
|
|
|
///
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### Example
|
2020-01-27 08:34:30 -06:00
|
|
|
/// ```rust,ignore
|
|
|
|
/// let _ = mutex.lock();
|
|
|
|
/// ```
|
|
|
|
///
|
2022-06-16 10:39:06 -05:00
|
|
|
/// Use instead:
|
2020-01-27 08:34:30 -06:00
|
|
|
/// ```rust,ignore
|
|
|
|
/// let _lock = mutex.lock();
|
|
|
|
/// ```
|
2021-12-06 05:33:31 -06:00
|
|
|
#[clippy::version = "1.43.0"]
|
2020-01-27 08:34:30 -06:00
|
|
|
pub LET_UNDERSCORE_LOCK,
|
|
|
|
correctness,
|
2022-11-21 13:34:47 -06:00
|
|
|
"non-binding `let` on a synchronization lock"
|
2020-01-27 08:34:30 -06:00
|
|
|
}
|
|
|
|
|
2020-11-23 06:51:04 -06:00
|
|
|
declare_clippy_lint! {
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### What it does
|
2022-11-21 13:34:47 -06:00
|
|
|
/// Checks for `let _ = <expr>` where the resulting type of expr implements `Future`
|
2020-11-23 06:51:04 -06:00
|
|
|
///
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### Why is this bad?
|
2022-11-21 13:34:47 -06:00
|
|
|
/// Futures must be polled for work to be done. The original intention was most likely to await the future
|
|
|
|
/// and ignore the resulting value.
|
2020-11-23 06:51:04 -06:00
|
|
|
///
|
2021-07-29 05:16:06 -05:00
|
|
|
/// ### Example
|
2022-06-16 10:39:06 -05:00
|
|
|
/// ```rust
|
2022-11-21 13:34:47 -06:00
|
|
|
/// async fn foo() -> Result<(), ()> {
|
|
|
|
/// Ok(())
|
2020-11-23 06:51:04 -06:00
|
|
|
/// }
|
2022-11-21 13:34:47 -06:00
|
|
|
/// let _ = foo();
|
2020-11-23 06:51:04 -06:00
|
|
|
/// ```
|
|
|
|
///
|
2022-06-16 10:39:06 -05:00
|
|
|
/// Use instead:
|
|
|
|
/// ```rust
|
2022-11-21 13:34:47 -06:00
|
|
|
/// # async fn context() {
|
|
|
|
/// async fn foo() -> Result<(), ()> {
|
|
|
|
/// Ok(())
|
2020-11-23 06:51:04 -06:00
|
|
|
/// }
|
2022-11-21 13:34:47 -06:00
|
|
|
/// let _ = foo().await;
|
|
|
|
/// # }
|
2020-11-23 06:51:04 -06:00
|
|
|
/// ```
|
2023-01-27 14:09:08 -06:00
|
|
|
#[clippy::version = "1.67.0"]
|
2022-11-21 13:34:47 -06:00
|
|
|
pub LET_UNDERSCORE_FUTURE,
|
|
|
|
suspicious,
|
|
|
|
"non-binding `let` on a future"
|
2020-11-23 06:51:04 -06:00
|
|
|
}
|
|
|
|
|
2022-11-21 13:34:47 -06:00
|
|
|
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
|
2022-10-23 08:18:45 -05:00
|
|
|
|
|
|
|
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
|
2022-06-30 03:50:09 -05:00
|
|
|
&paths::PARKING_LOT_MUTEX_GUARD,
|
|
|
|
&paths::PARKING_LOT_RWLOCK_READ_GUARD,
|
|
|
|
&paths::PARKING_LOT_RWLOCK_WRITE_GUARD,
|
2020-01-30 09:10:19 -06:00
|
|
|
];
|
2019-11-16 08:55:00 -06:00
|
|
|
|
2020-06-25 15:41:36 -05:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
|
|
|
fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
|
2022-11-21 13:34:47 -06:00
|
|
|
if !in_external_macro(cx.tcx.sess, local.span)
|
|
|
|
&& let PatKind::Wild = local.pat.kind
|
|
|
|
&& let Some(init) = local.init
|
|
|
|
{
|
|
|
|
let init_ty = cx.typeck_results().expr_ty(init);
|
|
|
|
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
|
|
|
|
GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)),
|
|
|
|
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
|
|
|
});
|
|
|
|
if contains_sync_guard {
|
|
|
|
span_lint_and_help(
|
|
|
|
cx,
|
|
|
|
LET_UNDERSCORE_LOCK,
|
|
|
|
local.span,
|
|
|
|
"non-binding `let` on a synchronization lock",
|
|
|
|
None,
|
|
|
|
"consider using an underscore-prefixed named \
|
2022-10-23 08:18:45 -05:00
|
|
|
binding or dropping explicitly with `std::mem::drop`",
|
2022-11-21 13:34:47 -06:00
|
|
|
);
|
|
|
|
} 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,
|
|
|
|
LET_UNDERSCORE_MUST_USE,
|
|
|
|
local.span,
|
|
|
|
"non-binding `let` on an expression with `#[must_use]` type",
|
|
|
|
None,
|
|
|
|
"consider explicitly using expression value",
|
|
|
|
);
|
|
|
|
} else if is_must_use_func_call(cx, init) {
|
|
|
|
span_lint_and_help(
|
|
|
|
cx,
|
|
|
|
LET_UNDERSCORE_MUST_USE,
|
|
|
|
local.span,
|
|
|
|
"non-binding `let` on a result of a `#[must_use]` function",
|
|
|
|
None,
|
|
|
|
"consider explicitly using function result",
|
|
|
|
);
|
2019-11-16 08:55:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|