11use super :: MUT_RANGE_BOUND ;
22use clippy_utils:: diagnostics:: span_lint;
3- use clippy_utils:: { higher, path_to_local} ;
3+ use clippy_utils:: { get_enclosing_block , higher, path_to_local} ;
44use 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 } ;
67use rustc_infer:: infer:: TyCtxtInferExt ;
78use rustc_lint:: LateContext ;
9+ use rustc_middle:: hir:: map:: Map ;
810use rustc_middle:: { mir:: FakeReadCause , ty} ;
911use rustc_span:: source_map:: Span ;
1012use rustc_typeck:: expr_use_visitor:: { Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
1113
1214pub ( 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 ) ;
1921 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 {
2124 let ( span_low, span_high) = check_for_mutation( cx, body, & mut_ids) ;
2225 mut_warn_with_span( cx, span_low) ;
2326 mut_warn_with_span( cx, span_high) ;
@@ -70,6 +73,7 @@ fn check_for_mutation<'tcx>(
7073 )
7174 . walk_expr ( body) ;
7275 } ) ;
76+
7377 delegate. mutation_span ( )
7478}
7579
@@ -87,10 +91,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
8791 fn borrow ( & mut self , cmt : & PlaceWithHirId < ' tcx > , diag_expr_id : HirId , bk : ty:: BorrowKind ) {
8892 if let ty:: BorrowKind :: MutBorrow = bk {
8993 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 ) {
9195 self . span_low = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
9296 }
93- if Some ( id) == self . hir_id_high {
97+ if Some ( id) == self . hir_id_high && ! BreakAfterExprVisitor :: is_found ( self . cx , diag_expr_id ) {
9498 self . span_high = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
9599 }
96100 }
@@ -99,10 +103,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
99103
100104 fn mutate ( & mut self , cmt : & PlaceWithHirId < ' tcx > , diag_expr_id : HirId ) {
101105 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 ) {
103107 self . span_low = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
104108 }
105- if Some ( id) == self . hir_id_high {
109+ if Some ( id) == self . hir_id_high && ! BreakAfterExprVisitor :: is_found ( self . cx , diag_expr_id ) {
106110 self . span_high = Some ( self . cx . tcx . hir ( ) . span ( diag_expr_id) ) ;
107111 }
108112 }
@@ -116,3 +120,49 @@ impl MutatePairDelegate<'_, '_> {
116120 ( self . span_low , self . span_high )
117121 }
118122}
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