1
1
use clippy_utils:: diagnostics:: { span_lint_and_then, span_lint_hir_and_then} ;
2
2
use clippy_utils:: source:: { snippet_opt, snippet_with_context} ;
3
3
use 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 } ;
5
5
use core:: ops:: ControlFlow ;
6
6
use if_chain:: if_chain;
7
7
use rustc_errors:: Applicability ;
@@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
151
151
kind : FnKind < ' tcx > ,
152
152
_: & ' tcx FnDecl < ' tcx > ,
153
153
body : & ' tcx Body < ' tcx > ,
154
- _ : Span ,
154
+ sp : Span ,
155
155
_: HirId ,
156
156
) {
157
157
match kind {
@@ -166,14 +166,14 @@ impl<'tcx> LateLintPass<'tcx> for Return {
166
166
check_final_expr ( cx, body. value , vec ! [ ] , replacement) ;
167
167
} ,
168
168
FnKind :: ItemFn ( ..) | FnKind :: Method ( ..) => {
169
- check_block_return ( cx, & body. value . kind , vec ! [ ] ) ;
169
+ check_block_return ( cx, & body. value . kind , sp , vec ! [ ] ) ;
170
170
} ,
171
171
}
172
172
}
173
173
}
174
174
175
175
// 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 > ) {
177
177
if let ExprKind :: Block ( block, _) = expr_kind {
178
178
if let Some ( block_expr) = block. expr {
179
179
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>,
183
183
check_final_expr ( cx, expr, semi_spans, RetReplacement :: Empty ) ;
184
184
} ,
185
185
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) ;
191
192
}
193
+ check_final_expr ( cx, semi_expr, semi_spans, RetReplacement :: Empty ) ;
192
194
} ,
193
195
_ => ( ) ,
194
196
}
@@ -231,9 +233,9 @@ fn check_final_expr<'tcx>(
231
233
emit_return_lint ( cx, ret_span, semi_spans, inner. as_ref ( ) . map ( |i| i. span ) , replacement) ;
232
234
} ,
233
235
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 ( ) ) ;
235
237
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) ;
237
239
}
238
240
} ,
239
241
// a match expr, check all arms
@@ -246,7 +248,7 @@ fn check_final_expr<'tcx>(
246
248
}
247
249
} ,
248
250
// 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) ,
250
252
}
251
253
}
252
254
0 commit comments