11use crate :: utils:: { is_direct_expn_of, span_lint} ;
2+ use core:: ops:: Deref ;
23use if_chain:: if_chain;
34use matches:: matches;
4- use rustc:: hir:: { Expr , ExprKind , Mutability , StmtKind , UnOp } ;
5+ use rustc:: hir:: { Expr , ExprKind , Guard , Mutability , StmtKind , UnOp } ;
56use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
67use rustc:: { declare_lint_pass, declare_tool_lint, ty} ;
78use syntax_pos:: Span ;
@@ -31,19 +32,67 @@ declare_clippy_lint! {
3132
3233declare_lint_pass ! ( DebugAssertWithMutCall => [ DEBUG_ASSERT_WITH_MUT_CALL ] ) ;
3334
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 > {
3536 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) )
41- } ,
42- ExprKind :: Path ( _) => cx. tables . adjustments ( ) . get ( e. hir_id ) . map_or ( false , |adj| {
43- adj. iter ( )
37+ ExprKind :: AddrOf ( Mutability :: MutMutable , _) => Some ( span) ,
38+ ExprKind :: Path ( _) => cx. tables . adjustments ( ) . get ( e. hir_id ) . and_then ( |adj| {
39+ if adj
40+ . iter ( )
4441 . any ( |a| matches ! ( a. target. kind, ty:: Ref ( _, _, Mutability :: MutMutable ) ) )
42+ {
43+ Some ( span)
44+ } else {
45+ None
46+ }
4547 } ) ,
46- _ => false ,
48+ ExprKind :: AddrOf ( Mutability :: MutImmutable , expr)
49+ | ExprKind :: Assign ( _, expr)
50+ | ExprKind :: AssignOp ( _, _, expr)
51+ | ExprKind :: Box ( expr)
52+ | ExprKind :: Break ( _, Some ( expr) )
53+ | ExprKind :: Cast ( expr, _)
54+ | ExprKind :: DropTemps ( expr)
55+ | ExprKind :: Field ( expr, _)
56+ | ExprKind :: Repeat ( expr, _)
57+ | ExprKind :: Ret ( Some ( expr) )
58+ | ExprKind :: Type ( expr, _)
59+ | ExprKind :: Unary ( _, expr)
60+ | ExprKind :: Yield ( expr, _) => check_for_mutable_call ( cx, expr. span , expr) ,
61+ ExprKind :: Binary ( _, lhs, rhs) | ExprKind :: Index ( lhs, rhs) => {
62+ check_for_mutable_call ( cx, lhs. span , lhs) . or_else ( || check_for_mutable_call ( cx, rhs. span , rhs) )
63+ } ,
64+ ExprKind :: Array ( args) | ExprKind :: Call ( _, args) | ExprKind :: MethodCall ( _, _, args) | ExprKind :: Tup ( args) => {
65+ ( * args) . iter ( ) . find_map ( |a| check_for_mutable_call ( cx, span, a) )
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+ } )
76+ } ) ,
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 ,
4796 }
4897}
4998
@@ -60,9 +109,7 @@ fn extract_call(cx: &LateContext<'_, '_>, e: &Expr) -> Option<Span> {
60109 if let ExprKind :: Unary ( UnOp :: UnNot , ref condition) = droptmp. kind;
61110 then {
62111 // 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)
66113 } else {
67114 // debug_assert_{eq,ne}
68115 if_chain! {
@@ -73,13 +120,13 @@ fn extract_call(cx: &LateContext<'_, '_>, e: &Expr) -> Option<Span> {
73120 if conditions. len( ) == 2 ;
74121 then {
75122 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) ;
78125 }
79126 }
80127 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) ;
83130 }
84131 }
85132 }
0 commit comments