1
1
use super :: MUT_RANGE_BOUND ;
2
2
use clippy_utils:: diagnostics:: span_lint;
3
- use clippy_utils:: { higher, path_to_local} ;
3
+ use clippy_utils:: { get_enclosing_block , higher, path_to_local} ;
4
4
use if_chain:: if_chain;
5
- use rustc_hir:: { BindingAnnotation , Expr , HirId , Node , PatKind } ;
5
+ use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
6
+ use rustc_hir:: { BindingAnnotation , Expr , ExprKind , HirId , Node , PatKind } ;
6
7
use rustc_infer:: infer:: TyCtxtInferExt ;
7
8
use rustc_lint:: LateContext ;
9
+ use rustc_middle:: hir:: map:: Map ;
8
10
use rustc_middle:: { mir:: FakeReadCause , ty} ;
9
11
use rustc_span:: source_map:: Span ;
10
12
use rustc_typeck:: expr_use_visitor:: { Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
11
13
12
14
pub ( super ) fn check ( cx : & LateContext < ' _ > , arg : & Expr < ' _ > , body : & Expr < ' _ > ) {
13
- if let Some ( higher :: Range {
14
- start : Some ( start ) ,
15
- end : Some ( end ) ,
16
- ..
17
- } ) = higher :: range ( arg )
18
- {
15
+ if_chain ! {
16
+ if let Some ( higher :: Range {
17
+ start : Some ( start ) ,
18
+ end : Some ( end ) ,
19
+ ..
20
+ } ) = higher :: range ( arg ) ;
19
21
let mut_ids = vec![ check_for_mutability( cx, start) , check_for_mutability( cx, end) ] ;
20
- if mut_ids[ 0 ] . is_some ( ) || mut_ids[ 1 ] . is_some ( ) {
22
+ if mut_ids[ 0 ] . is_some( ) || mut_ids[ 1 ] . is_some( ) ;
23
+ then {
21
24
let ( span_low, span_high) = check_for_mutation( cx, body, & mut_ids) ;
22
25
mut_warn_with_span( cx, span_low) ;
23
26
mut_warn_with_span( cx, span_high) ;
@@ -70,6 +73,7 @@ fn check_for_mutation<'tcx>(
70
73
)
71
74
. walk_expr ( body) ;
72
75
} ) ;
76
+
73
77
delegate. mutation_span ( )
74
78
}
75
79
@@ -87,10 +91,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
87
91
fn borrow ( & mut self , cmt : & PlaceWithHirId < ' tcx > , diag_expr_id : HirId , bk : ty:: BorrowKind ) {
88
92
if let ty:: BorrowKind :: MutBorrow = bk {
89
93
if let PlaceBase :: Local ( id) = cmt. place . base {
90
- if Some ( id) == self . hir_id_low {
94
+ if Some ( id) == self . hir_id_low && ! BreakAfterExprVisitor :: is_found ( self . cx , diag_expr_id ) {
91
95
self . span_low = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
92
96
}
93
- if Some ( id) == self . hir_id_high {
97
+ if Some ( id) == self . hir_id_high && ! BreakAfterExprVisitor :: is_found ( self . cx , diag_expr_id ) {
94
98
self . span_high = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
95
99
}
96
100
}
@@ -99,10 +103,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
99
103
100
104
fn mutate ( & mut self , cmt : & PlaceWithHirId < ' tcx > , diag_expr_id : HirId ) {
101
105
if let PlaceBase :: Local ( id) = cmt. place . base {
102
- if Some ( id) == self . hir_id_low {
106
+ if Some ( id) == self . hir_id_low && ! BreakAfterExprVisitor :: is_found ( self . cx , diag_expr_id ) {
103
107
self . span_low = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
104
108
}
105
- if Some ( id) == self . hir_id_high {
109
+ if Some ( id) == self . hir_id_high && ! BreakAfterExprVisitor :: is_found ( self . cx , diag_expr_id ) {
106
110
self . span_high = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
107
111
}
108
112
}
@@ -116,3 +120,49 @@ impl MutatePairDelegate<'_, '_> {
116
120
( self . span_low , self . span_high )
117
121
}
118
122
}
123
+
124
+ struct BreakAfterExprVisitor {
125
+ hir_id : HirId ,
126
+ past_expr : bool ,
127
+ break_after_expr : bool ,
128
+ }
129
+
130
+ impl BreakAfterExprVisitor {
131
+ pub fn is_found ( cx : & LateContext < ' _ > , hir_id : HirId ) -> bool {
132
+ let mut visitor = BreakAfterExprVisitor {
133
+ hir_id,
134
+ past_expr : false ,
135
+ break_after_expr : false ,
136
+ } ;
137
+
138
+ get_enclosing_block ( cx, hir_id) . map_or ( false , |block| {
139
+ visitor. visit_block ( block) ;
140
+ visitor. break_after_expr
141
+ } )
142
+ }
143
+ }
144
+
145
+ impl intravisit:: Visitor < ' tcx > for BreakAfterExprVisitor {
146
+ type Map = Map < ' tcx > ;
147
+
148
+ fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
149
+ NestedVisitorMap :: None
150
+ }
151
+
152
+ fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
153
+ if self . break_after_expr {
154
+ return ;
155
+ }
156
+ if matches ! ( & expr. kind, ExprKind :: If ( ..) ) || matches ! ( & expr. kind, ExprKind :: Match ( ..) ) {
157
+ return ;
158
+ }
159
+
160
+ if expr. hir_id == self . hir_id {
161
+ self . past_expr = true ;
162
+ } else if self . past_expr && matches ! ( & expr. kind, ExprKind :: Break ( ..) ) {
163
+ self . break_after_expr = true ;
164
+ } else {
165
+ intravisit:: walk_expr ( self , expr) ;
166
+ }
167
+ }
168
+ }
0 commit comments