1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: ty:: is_type_diagnostic_item;
3
+ use clippy_utils:: visitors:: for_each_expr_without_closures;
3
4
use clippy_utils:: { higher, SpanlessEq } ;
5
+ use core:: ops:: ControlFlow ;
4
6
use rustc_errors:: Diag ;
5
- use rustc_hir:: intravisit:: { self as visit, Visitor } ;
6
7
use rustc_hir:: { Expr , ExprKind } ;
7
8
use rustc_lint:: { LateContext , LateLintPass } ;
8
9
use rustc_session:: declare_lint_pass;
@@ -44,21 +45,27 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
44
45
45
46
impl < ' tcx > LateLintPass < ' tcx > for IfLetMutex {
46
47
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
47
- let mut arm_visit = ArmVisitor { found_mutex : None , cx } ;
48
- let mut op_visit = OppVisitor { found_mutex : None , cx } ;
49
48
if let Some ( higher:: IfLet {
50
49
let_expr,
51
50
if_then,
52
51
if_else : Some ( if_else) ,
53
52
..
54
53
} ) = higher:: IfLet :: hir ( cx, expr)
55
54
{
56
- op_visit. visit_expr ( let_expr) ;
57
- if let Some ( op_mutex) = op_visit. found_mutex {
58
- arm_visit. visit_expr ( if_then) ;
59
- arm_visit. visit_expr ( if_else) ;
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
+ } ;
60
62
61
- if let Some ( arm_mutex) = arm_visit. found_mutex_if_same_as ( op_mutex) {
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
+ {
62
69
let diag = |diag : & mut Diag < ' _ , ( ) > | {
63
70
diag. span_label (
64
71
op_mutex. span ,
@@ -83,48 +90,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
83
90
}
84
91
}
85
92
86
- /// Checks if `Mutex::lock` is called in the `if let` expr.
87
- pub struct OppVisitor < ' a , ' tcx > {
88
- found_mutex : Option < & ' tcx Expr < ' tcx > > ,
89
- cx : & ' a LateContext < ' tcx > ,
90
- }
91
-
92
- impl < ' tcx > Visitor < ' tcx > for OppVisitor < ' _ , ' tcx > {
93
- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' _ > ) {
94
- if let Some ( mutex) = is_mutex_lock_call ( self . cx , expr) {
95
- self . found_mutex = Some ( mutex) ;
96
- return ;
97
- }
98
- visit:: walk_expr ( self , expr) ;
99
- }
100
- }
101
-
102
- /// Checks if `Mutex::lock` is called in any of the branches.
103
- pub struct ArmVisitor < ' a , ' tcx > {
104
- found_mutex : Option < & ' tcx Expr < ' tcx > > ,
105
- cx : & ' a LateContext < ' tcx > ,
106
- }
107
-
108
- impl < ' tcx > Visitor < ' tcx > for ArmVisitor < ' _ , ' tcx > {
109
- fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
110
- if let Some ( mutex) = is_mutex_lock_call ( self . cx , expr) {
111
- self . found_mutex = Some ( mutex) ;
112
- return ;
113
- }
114
- visit:: walk_expr ( self , expr) ;
115
- }
116
- }
117
-
118
- impl < ' tcx , ' l > ArmVisitor < ' tcx , ' l > {
119
- fn found_mutex_if_same_as ( & self , op_mutex : & Expr < ' _ > ) -> Option < & Expr < ' _ > > {
120
- self . found_mutex . and_then ( |arm_mutex| {
121
- SpanlessEq :: new ( self . cx )
122
- . eq_expr ( op_mutex, arm_mutex)
123
- . then_some ( arm_mutex)
124
- } )
125
- }
126
- }
127
-
128
93
fn is_mutex_lock_call < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) -> Option < & ' tcx Expr < ' tcx > > {
129
94
if let ExprKind :: MethodCall ( path, self_arg, ..) = & expr. kind
130
95
&& path. ident . as_str ( ) == "lock"
0 commit comments