Skip to content

Commit 1a1c978

Browse files
committed
[if_let_mutex]: make the mutex check part of the expr visitor
1 parent 668b659 commit 1a1c978

File tree

3 files changed

+42
-21
lines changed

3 files changed

+42
-21
lines changed

clippy_lints/src/if_let_mutex.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::ty::is_type_diagnostic_item;
33
use clippy_utils::visitors::for_each_expr_without_closures;
4-
use clippy_utils::{higher, SpanlessEq};
4+
use clippy_utils::{eq_expr_value, higher};
55
use core::ops::ControlFlow;
66
use rustc_errors::Diag;
77
use rustc_hir::{Expr, ExprKind};
@@ -52,20 +52,11 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
5252
..
5353
}) = higher::IfLet::hir(cx, expr)
5454
{
55-
let is_mutex_lock = |e: &'tcx Expr<'tcx>| {
56-
if let Some(mutex) = is_mutex_lock_call(cx, e) {
57-
ControlFlow::Break(mutex)
58-
} else {
59-
ControlFlow::Continue(())
60-
}
61-
};
62-
63-
let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock);
55+
let op_mutex = for_each_expr_without_closures(let_expr, |e| mutex_lock_call(cx, e, None));
6456
if let Some(op_mutex) = op_mutex {
65-
let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock);
66-
if let Some(arm_mutex) = arm_mutex
67-
&& SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)
68-
{
57+
let arm_mutex =
58+
for_each_expr_without_closures((if_then, if_else), |e| mutex_lock_call(cx, e, Some(op_mutex)));
59+
if let Some(arm_mutex) = arm_mutex {
6960
let diag = |diag: &mut Diag<'_, ()>| {
7061
diag.span_label(
7162
op_mutex.span,
@@ -90,14 +81,19 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
9081
}
9182
}
9283

93-
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
84+
fn mutex_lock_call<'tcx>(
85+
cx: &LateContext<'tcx>,
86+
expr: &'tcx Expr<'_>,
87+
op_mutex: Option<&'tcx Expr<'_>>,
88+
) -> ControlFlow<&'tcx Expr<'tcx>> {
9489
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
9590
&& path.ident.as_str() == "lock"
9691
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
9792
&& is_type_diagnostic_item(cx, ty, sym::Mutex)
93+
&& op_mutex.map_or(true, |op| eq_expr_value(cx, self_arg, op))
9894
{
99-
Some(self_arg)
95+
ControlFlow::Break(self_arg)
10096
} else {
101-
None
97+
ControlFlow::Continue(())
10298
}
10399
}

tests/ui/if_let_mutex.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::if_let_mutex)]
2+
#![allow(clippy::redundant_pattern_matching)]
23

34
use std::ops::Deref;
45
use std::sync::Mutex;
@@ -50,4 +51,12 @@ fn mutex_ref(mutex: &Mutex<i32>) {
5051
};
5152
}
5253

54+
fn multiple_mutexes(m1: &Mutex<()>, m2: &Mutex<()>) {
55+
if let Ok(_) = m1.lock() {
56+
m2.lock();
57+
} else {
58+
m1.lock();
59+
}
60+
}
61+
5362
fn main() {}

tests/ui/if_let_mutex.stderr

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
2-
--> tests/ui/if_let_mutex.rs:10:5
2+
--> tests/ui/if_let_mutex.rs:11:5
33
|
44
LL | if let Err(locked) = m.lock() {
55
| ^ - this Mutex will remain locked for the entire `if let`-block...
@@ -19,7 +19,7 @@ LL | | };
1919
= help: to override `-D warnings` add `#[allow(clippy::if_let_mutex)]`
2020

2121
error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
22-
--> tests/ui/if_let_mutex.rs:23:5
22+
--> tests/ui/if_let_mutex.rs:24:5
2323
|
2424
LL | if let Some(locked) = m.lock().unwrap().deref() {
2525
| ^ - this Mutex will remain locked for the entire `if let`-block...
@@ -37,7 +37,7 @@ LL | | };
3737
= help: move the lock call outside of the `if let ...` expression
3838

3939
error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
40-
--> tests/ui/if_let_mutex.rs:45:5
40+
--> tests/ui/if_let_mutex.rs:46:5
4141
|
4242
LL | if let Ok(i) = mutex.lock() {
4343
| ^ ----- this Mutex will remain locked for the entire `if let`-block...
@@ -53,5 +53,21 @@ LL | | };
5353
|
5454
= help: move the lock call outside of the `if let ...` expression
5555

56-
error: aborting due to 3 previous errors
56+
error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
57+
--> tests/ui/if_let_mutex.rs:55:5
58+
|
59+
LL | if let Ok(_) = m1.lock() {
60+
| ^ -- this Mutex will remain locked for the entire `if let`-block...
61+
| _____|
62+
| |
63+
LL | | m2.lock();
64+
LL | | } else {
65+
LL | | m1.lock();
66+
| | -- ... and is tried to lock again here, which will always deadlock.
67+
LL | | }
68+
| |_____^
69+
|
70+
= help: move the lock call outside of the `if let ...` expression
71+
72+
error: aborting due to 4 previous errors
5773

0 commit comments

Comments
 (0)