|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_then;
|
2 | 2 | use clippy_utils::ty::is_type_diagnostic_item;
|
3 | 3 | use clippy_utils::visitors::for_each_expr_without_closures;
|
4 |
| -use clippy_utils::{higher, SpanlessEq}; |
| 4 | +use clippy_utils::{eq_expr_value, higher}; |
5 | 5 | use core::ops::ControlFlow;
|
6 | 6 | use rustc_errors::Diag;
|
7 | 7 | use rustc_hir::{Expr, ExprKind};
|
@@ -51,53 +51,45 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
|
51 | 51 | if_else: Some(if_else),
|
52 | 52 | ..
|
53 | 53 | }) = higher::IfLet::hir(cx, expr)
|
| 54 | + && let Some(op_mutex) = for_each_expr_without_closures(let_expr, |e| mutex_lock_call(cx, e, None)) |
| 55 | + && let Some(arm_mutex) = |
| 56 | + for_each_expr_without_closures((if_then, if_else), |e| mutex_lock_call(cx, e, Some(op_mutex))) |
54 | 57 | {
|
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 |
| - } |
| 58 | + let diag = |diag: &mut Diag<'_, ()>| { |
| 59 | + diag.span_label( |
| 60 | + op_mutex.span, |
| 61 | + "this Mutex will remain locked for the entire `if let`-block...", |
| 62 | + ); |
| 63 | + diag.span_label( |
| 64 | + arm_mutex.span, |
| 65 | + "... and is tried to lock again here, which will always deadlock.", |
| 66 | + ); |
| 67 | + diag.help("move the lock call outside of the `if let ...` expression"); |
61 | 68 | };
|
62 |
| - |
63 |
| - let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock); |
64 |
| - 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 |
| - { |
69 |
| - let diag = |diag: &mut Diag<'_, ()>| { |
70 |
| - diag.span_label( |
71 |
| - op_mutex.span, |
72 |
| - "this Mutex will remain locked for the entire `if let`-block...", |
73 |
| - ); |
74 |
| - diag.span_label( |
75 |
| - arm_mutex.span, |
76 |
| - "... and is tried to lock again here, which will always deadlock.", |
77 |
| - ); |
78 |
| - diag.help("move the lock call outside of the `if let ...` expression"); |
79 |
| - }; |
80 |
| - span_lint_and_then( |
81 |
| - cx, |
82 |
| - IF_LET_MUTEX, |
83 |
| - expr.span, |
84 |
| - "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock", |
85 |
| - diag, |
86 |
| - ); |
87 |
| - } |
88 |
| - } |
| 69 | + span_lint_and_then( |
| 70 | + cx, |
| 71 | + IF_LET_MUTEX, |
| 72 | + expr.span, |
| 73 | + "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock", |
| 74 | + diag, |
| 75 | + ); |
89 | 76 | }
|
90 | 77 | }
|
91 | 78 | }
|
92 | 79 |
|
93 |
| -fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { |
| 80 | +fn mutex_lock_call<'tcx>( |
| 81 | + cx: &LateContext<'tcx>, |
| 82 | + expr: &'tcx Expr<'_>, |
| 83 | + op_mutex: Option<&'tcx Expr<'_>>, |
| 84 | +) -> ControlFlow<&'tcx Expr<'tcx>> { |
94 | 85 | if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
|
95 | 86 | && path.ident.as_str() == "lock"
|
96 | 87 | && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
|
97 | 88 | && is_type_diagnostic_item(cx, ty, sym::Mutex)
|
| 89 | + && op_mutex.map_or(true, |op| eq_expr_value(cx, self_arg, op)) |
98 | 90 | {
|
99 |
| - Some(self_arg) |
| 91 | + ControlFlow::Break(self_arg) |
100 | 92 | } else {
|
101 |
| - None |
| 93 | + ControlFlow::Continue(()) |
102 | 94 | }
|
103 | 95 | }
|
0 commit comments