1
1
use crate :: utils:: { is_direct_expn_of, span_lint} ;
2
+ use core:: ops:: Deref ;
2
3
use if_chain:: if_chain;
3
4
use matches:: matches;
4
- use rustc:: hir:: { Expr , ExprKind , Mutability , StmtKind , UnOp } ;
5
+ use rustc:: hir:: { Expr , ExprKind , Guard , Mutability , StmtKind , UnOp } ;
5
6
use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
6
7
use rustc:: { declare_lint_pass, declare_tool_lint, ty} ;
7
8
use syntax_pos:: Span ;
@@ -31,19 +32,67 @@ declare_clippy_lint! {
31
32
32
33
declare_lint_pass ! ( DebugAssertWithMutCall => [ DEBUG_ASSERT_WITH_MUT_CALL ] ) ;
33
34
34
- fn check_for_mutable_call ( cx : & LateContext < ' _ , ' _ > , e : & Expr ) -> bool {
35
+ fn check_for_mutable_call ( cx : & LateContext < ' _ , ' _ > , span : Span , e : & Expr ) -> Option < Span > {
35
36
match & e. kind {
36
- ExprKind :: AddrOf ( Mutability :: MutMutable , _) => true ,
37
- ExprKind :: AddrOf ( Mutability :: MutImmutable , expr) | ExprKind :: Unary ( _, expr) => check_for_mutable_call ( cx, expr) ,
38
- ExprKind :: Binary ( _, lhs, rhs) => check_for_mutable_call ( cx, lhs) | check_for_mutable_call ( cx, rhs) ,
39
- ExprKind :: Call ( _, args) | ExprKind :: MethodCall ( _, _, args) => {
40
- ( * args) . iter ( ) . any ( |a| check_for_mutable_call ( cx, a) )
37
+ ExprKind :: AddrOf ( Mutability :: MutMutable , _) => Some ( span) ,
38
+ ExprKind :: AddrOf ( Mutability :: MutImmutable , expr)
39
+ | ExprKind :: Assign ( _, expr)
40
+ | ExprKind :: AssignOp ( _, _, expr)
41
+ | ExprKind :: Box ( expr)
42
+ | ExprKind :: Break ( _, Some ( expr) )
43
+ | ExprKind :: Cast ( expr, _)
44
+ | ExprKind :: DropTemps ( expr)
45
+ | ExprKind :: Field ( expr, _)
46
+ | ExprKind :: Repeat ( expr, _)
47
+ | ExprKind :: Ret ( Some ( expr) )
48
+ | ExprKind :: Type ( expr, _)
49
+ | ExprKind :: Unary ( _, expr)
50
+ | ExprKind :: Yield ( expr, _) => check_for_mutable_call ( cx, expr. span , expr) ,
51
+ ExprKind :: Binary ( _, lhs, rhs) | ExprKind :: Index ( lhs, rhs) => {
52
+ check_for_mutable_call ( cx, lhs. span , lhs) . or_else ( || check_for_mutable_call ( cx, rhs. span , rhs) )
41
53
} ,
42
- ExprKind :: Path ( _) => cx. tables . adjustments ( ) . get ( e. hir_id ) . map_or ( false , |adj| {
43
- adj. iter ( )
54
+ ExprKind :: Array ( args) | ExprKind :: Call ( _, args) | ExprKind :: MethodCall ( _, _, args) | ExprKind :: Tup ( args) => {
55
+ ( * args) . iter ( ) . find_map ( |a| check_for_mutable_call ( cx, span, a) )
56
+ } ,
57
+ ExprKind :: Path ( _) => cx. tables . adjustments ( ) . get ( e. hir_id ) . and_then ( |adj| {
58
+ if adj
59
+ . iter ( )
44
60
. any ( |a| matches ! ( a. target. kind, ty:: Ref ( _, _, Mutability :: MutMutable ) ) )
61
+ {
62
+ Some ( span)
63
+ } else {
64
+ None
65
+ }
66
+ } ) ,
67
+ ExprKind :: Match ( header, arm, _) => check_for_mutable_call ( cx, header. span , header) . or_else ( || {
68
+ ( * arm) . iter ( ) . find_map ( |a| {
69
+ check_for_mutable_call ( cx, a. body . span , & a. body ) . or_else ( || {
70
+ a. guard . as_ref ( ) . and_then ( |g| {
71
+ let Guard :: If ( e) = g;
72
+ check_for_mutable_call ( cx, e. span , & e)
73
+ } )
74
+ } )
75
+ } )
45
76
} ) ,
46
- _ => false ,
77
+ ExprKind :: Block ( block, _) | ExprKind :: Loop ( block, _, _) => block
78
+ . stmts
79
+ . iter ( )
80
+ . filter_map ( |s| match & s. kind {
81
+ StmtKind :: Local ( l) => l. init . as_ref ( ) . map ( |x| x. deref ( ) ) ,
82
+ StmtKind :: Expr ( e) => Some ( e) ,
83
+ StmtKind :: Semi ( e) => Some ( e) ,
84
+ StmtKind :: Item ( _) => None ,
85
+ } )
86
+ . chain ( block. expr . as_ref ( ) . map ( |x| x. deref ( ) ) )
87
+ . find_map ( |a| check_for_mutable_call ( cx, a. span , a) ) ,
88
+ ExprKind :: Err
89
+ | ExprKind :: Lit ( _)
90
+ | ExprKind :: Continue ( _)
91
+ | ExprKind :: InlineAsm ( _, _, _)
92
+ | ExprKind :: Struct ( _, _, _)
93
+ | ExprKind :: Closure ( _, _, _, _, _)
94
+ | ExprKind :: Break ( _, None )
95
+ | ExprKind :: Ret ( None ) => None ,
47
96
}
48
97
}
49
98
@@ -60,9 +109,7 @@ fn extract_call(cx: &LateContext<'_, '_>, e: &Expr) -> Option<Span> {
60
109
if let ExprKind :: Unary ( UnOp :: UnNot , ref condition) = droptmp. kind;
61
110
then {
62
111
// debug_assert
63
- if check_for_mutable_call( cx, condition) {
64
- return Some ( condition. span) ;
65
- }
112
+ return check_for_mutable_call( cx, condition. span, condition)
66
113
} else {
67
114
// debug_assert_{eq,ne}
68
115
if_chain! {
@@ -73,13 +120,13 @@ fn extract_call(cx: &LateContext<'_, '_>, e: &Expr) -> Option<Span> {
73
120
if conditions. len( ) == 2 ;
74
121
then {
75
122
if let ExprKind :: AddrOf ( _, ref lhs) = conditions[ 0 ] . kind {
76
- if check_for_mutable_call( cx, lhs) {
77
- return Some ( lhs . span) ;
123
+ if let Some ( span ) = check_for_mutable_call( cx, lhs . span , lhs) {
124
+ return Some ( span) ;
78
125
}
79
126
}
80
127
if let ExprKind :: AddrOf ( _, ref rhs) = conditions[ 1 ] . kind {
81
- if check_for_mutable_call( cx, rhs) {
82
- return Some ( rhs . span) ;
128
+ if let Some ( span ) = check_for_mutable_call( cx, rhs . span , rhs) {
129
+ return Some ( span) ;
83
130
}
84
131
}
85
132
}
0 commit comments