11use crate :: utils:: { match_type, paths, span_lint_and_help} ;
22use if_chain:: if_chain;
3- use rustc_hir:: { Expr , ExprKind , MatchSource , StmtKind } ;
3+ use rustc_hir:: { Arm , Expr , ExprKind , MatchSource , Stmt , StmtKind } ;
44use rustc_lint:: { LateContext , LateLintPass } ;
55use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
66
@@ -11,7 +11,7 @@ declare_clippy_lint! {
1111 /// **Why is this bad?** The Mutex lock remains held for the whole
1212 /// `if let ... else` block and deadlocks.
1313 ///
14- /// **Known problems:** This lint does not generate an auto-applicable suggestion .
14+ /// **Known problems:** None .
1515 ///
1616 /// **Example:**
1717 ///
@@ -49,47 +49,7 @@ impl LateLintPass<'_, '_> for IfLetMutex {
4949 if match_type( cx, ty, & paths:: MUTEX ) ; // make sure receiver is Mutex
5050 if method_chain_names( op, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
5151
52- if arms. iter( ) . any( |arm| if_chain! {
53- if let ExprKind :: Block ( ref block, _l) = arm. body. kind;
54- if block. stmts. iter( ) . any( |stmt| match stmt. kind {
55- StmtKind :: Local ( l) => if_chain! {
56- if let Some ( ex) = l. init;
57- if let ExprKind :: MethodCall ( _, _, _) = op. kind;
58- if method_chain_names( ex, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
59- then {
60- match_type_method_chain( cx, ex, 5 )
61- } else {
62- false
63- }
64- } ,
65- StmtKind :: Expr ( e) => if_chain! {
66- if let ExprKind :: MethodCall ( _, _, _) = e. kind;
67- if method_chain_names( e, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
68- then {
69- match_type_method_chain( cx, ex, 5 )
70- } else {
71- false
72- }
73- } ,
74- StmtKind :: Semi ( e) => if_chain! {
75- if let ExprKind :: MethodCall ( _, _, _) = e. kind;
76- if method_chain_names( e, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
77- then {
78- match_type_method_chain( cx, ex, 5 )
79- } else {
80- false
81- }
82- } ,
83- _ => {
84- false
85- } ,
86- } ) ;
87- then {
88- true
89- } else {
90- false
91- }
92- } ) ;
52+ if arms. iter( ) . any( |arm| matching_arm( arm, op, ex, cx) ) ;
9353 then {
9454 span_lint_and_help(
9555 cx,
@@ -103,6 +63,52 @@ impl LateLintPass<'_, '_> for IfLetMutex {
10363 }
10464}
10565
66+ fn matching_arm ( arm : & Arm < ' _ > , op : & Expr < ' _ > , ex : & Expr < ' _ > , cx : & LateContext < ' _ , ' _ > ) -> bool {
67+ if_chain ! {
68+ if let ExprKind :: Block ( ref block, _l) = arm. body. kind;
69+ if block. stmts. iter( ) . any( |stmt| matching_stmt( stmt, op, ex, cx) ) ;
70+ then {
71+ true
72+ } else {
73+ false
74+ }
75+ }
76+ }
77+
78+ fn matching_stmt ( stmt : & Stmt < ' _ > , op : & Expr < ' _ > , ex : & Expr < ' _ > , cx : & LateContext < ' _ , ' _ > ) -> bool {
79+ match stmt. kind {
80+ StmtKind :: Local ( l) => if_chain ! {
81+ if let Some ( ex) = l. init;
82+ if let ExprKind :: MethodCall ( _, _, _) = op. kind;
83+ if method_chain_names( ex, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
84+ then {
85+ match_type_method_chain( cx, ex, 5 )
86+ } else {
87+ false
88+ }
89+ } ,
90+ StmtKind :: Expr ( e) => if_chain ! {
91+ if let ExprKind :: MethodCall ( _, _, _) = e. kind;
92+ if method_chain_names( e, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
93+ then {
94+ match_type_method_chain( cx, ex, 5 )
95+ } else {
96+ false
97+ }
98+ } ,
99+ StmtKind :: Semi ( e) => if_chain ! {
100+ if let ExprKind :: MethodCall ( _, _, _) = e. kind;
101+ if method_chain_names( e, 10 ) . iter( ) . any( |s| s == "lock" ) ; // and lock is called
102+ then {
103+ match_type_method_chain( cx, ex, 5 )
104+ } else {
105+ false
106+ }
107+ } ,
108+ _ => false ,
109+ }
110+ }
111+
106112/// Return the names of `max_depth` number of methods called in the chain.
107113fn method_chain_names < ' tcx > ( expr : & ' tcx Expr < ' tcx > , max_depth : usize ) -> Vec < String > {
108114 let mut method_names = Vec :: with_capacity ( max_depth) ;
0 commit comments