11use clippy_utils:: diagnostics:: { span_lint_and_then, span_lint_hir_and_then} ;
22use clippy_utils:: source:: { snippet_opt, snippet_with_context} ;
33use clippy_utils:: visitors:: { for_each_expr, Descend } ;
4- use clippy_utils:: { fn_def_id, path_to_local_id} ;
4+ use clippy_utils:: { fn_def_id, path_to_local_id, span_find_starting_semi } ;
55use core:: ops:: ControlFlow ;
66use if_chain:: if_chain;
77use rustc_errors:: Applicability ;
@@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
151151 kind : FnKind < ' tcx > ,
152152 _: & ' tcx FnDecl < ' tcx > ,
153153 body : & ' tcx Body < ' tcx > ,
154- _ : Span ,
154+ sp : Span ,
155155 _: HirId ,
156156 ) {
157157 match kind {
@@ -166,14 +166,14 @@ impl<'tcx> LateLintPass<'tcx> for Return {
166166 check_final_expr ( cx, body. value , vec ! [ ] , replacement) ;
167167 } ,
168168 FnKind :: ItemFn ( ..) | FnKind :: Method ( ..) => {
169- check_block_return ( cx, & body. value . kind , vec ! [ ] ) ;
169+ check_block_return ( cx, & body. value . kind , sp , vec ! [ ] ) ;
170170 } ,
171171 }
172172 }
173173}
174174
175175// if `expr` is a block, check if there are needless returns in it
176- fn check_block_return < ' tcx > ( cx : & LateContext < ' tcx > , expr_kind : & ExprKind < ' tcx > , semi_spans : Vec < Span > ) {
176+ fn check_block_return < ' tcx > ( cx : & LateContext < ' tcx > , expr_kind : & ExprKind < ' tcx > , sp : Span , mut semi_spans : Vec < Span > ) {
177177 if let ExprKind :: Block ( block, _) = expr_kind {
178178 if let Some ( block_expr) = block. expr {
179179 check_final_expr ( cx, block_expr, semi_spans, RetReplacement :: Empty ) ;
@@ -183,12 +183,14 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
183183 check_final_expr ( cx, expr, semi_spans, RetReplacement :: Empty ) ;
184184 } ,
185185 StmtKind :: Semi ( semi_expr) => {
186- let mut semi_spans_and_this_one = semi_spans;
187- // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382`
188- if let Some ( semicolon_span) = stmt. span . trim_start ( semi_expr. span ) {
189- semi_spans_and_this_one. push ( semicolon_span) ;
190- check_final_expr ( cx, semi_expr, semi_spans_and_this_one, RetReplacement :: Empty ) ;
186+ // Remove ending semicolons and any whitespace ' ' in between.
187+ // Without `return`, the suggestion might not compile if the semicolon is retained
188+ if let Some ( semi_span) = stmt. span . trim_start ( semi_expr. span ) {
189+ let semi_span_to_remove =
190+ span_find_starting_semi ( cx. sess ( ) . source_map ( ) , semi_span. with_hi ( sp. hi ( ) ) ) ;
191+ semi_spans. push ( semi_span_to_remove) ;
191192 }
193+ check_final_expr ( cx, semi_expr, semi_spans, RetReplacement :: Empty ) ;
192194 } ,
193195 _ => ( ) ,
194196 }
@@ -231,9 +233,9 @@ fn check_final_expr<'tcx>(
231233 emit_return_lint ( cx, ret_span, semi_spans, inner. as_ref ( ) . map ( |i| i. span ) , replacement) ;
232234 } ,
233235 ExprKind :: If ( _, then, else_clause_opt) => {
234- check_block_return ( cx, & then. kind , semi_spans. clone ( ) ) ;
236+ check_block_return ( cx, & then. kind , peeled_drop_expr . span , semi_spans. clone ( ) ) ;
235237 if let Some ( else_clause) = else_clause_opt {
236- check_block_return ( cx, & else_clause. kind , semi_spans) ;
238+ check_block_return ( cx, & else_clause. kind , peeled_drop_expr . span , semi_spans) ;
237239 }
238240 } ,
239241 // a match expr, check all arms
@@ -246,7 +248,7 @@ fn check_final_expr<'tcx>(
246248 }
247249 } ,
248250 // if it's a whole block, check it
249- other_expr_kind => check_block_return ( cx, other_expr_kind, semi_spans) ,
251+ other_expr_kind => check_block_return ( cx, other_expr_kind, peeled_drop_expr . span , semi_spans) ,
250252 }
251253}
252254
0 commit comments