@@ -14,6 +14,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
14
14
use rustc_span:: def_id:: LocalDefId ;
15
15
use rustc_span:: source_map:: Span ;
16
16
use rustc_span:: { BytePos , Pos } ;
17
+ use std:: borrow:: Cow ;
17
18
18
19
declare_clippy_lint ! {
19
20
/// ### What it does
@@ -70,33 +71,39 @@ declare_clippy_lint! {
70
71
}
71
72
72
73
#[ derive( PartialEq , Eq , Clone ) ]
73
- enum RetReplacement {
74
+ enum RetReplacement < ' tcx > {
74
75
Empty ,
75
76
Block ,
76
77
Unit ,
77
- IfSequence ( String ) ,
78
- Expr ( String ) ,
78
+ IfSequence ( Cow < ' tcx , str > , Applicability ) ,
79
+ Expr ( Cow < ' tcx , str > , Applicability ) ,
79
80
}
80
81
81
- impl RetReplacement {
82
+ impl < ' tcx > RetReplacement < ' tcx > {
82
83
fn sugg_help ( self ) -> & ' static str {
83
84
match self {
84
- Self :: Empty | Self :: Expr ( _ ) => "remove `return`" ,
85
+ Self :: Empty | Self :: Expr ( .. ) => "remove `return`" ,
85
86
Self :: Block => "replace `return` with an empty block" ,
86
87
Self :: Unit => "replace `return` with a unit value" ,
87
- Self :: IfSequence ( _) => "remove `return` and wrap the sequence with parentheses" ,
88
+ Self :: IfSequence ( ..) => "remove `return` and wrap the sequence with parentheses" ,
89
+ }
90
+ }
91
+ fn applicability ( & self ) -> Option < Applicability > {
92
+ match self {
93
+ Self :: Expr ( _, ap) | Self :: IfSequence ( _, ap) => Some ( * ap) ,
94
+ _ => None ,
88
95
}
89
96
}
90
97
}
91
98
92
- impl ToString for RetReplacement {
99
+ impl < ' tcx > ToString for RetReplacement < ' tcx > {
93
100
fn to_string ( & self ) -> String {
94
101
match self {
95
102
Self :: Empty => String :: new ( ) ,
96
103
Self :: Block => "{}" . to_string ( ) ,
97
104
Self :: Unit => "()" . to_string ( ) ,
98
- Self :: IfSequence ( inner) => format ! ( "({inner})" ) ,
99
- Self :: Expr ( inner) => inner. clone ( ) ,
105
+ Self :: IfSequence ( inner, _ ) => format ! ( "({inner})" ) ,
106
+ Self :: Expr ( inner, _ ) => inner. to_string ( ) ,
100
107
}
101
108
}
102
109
}
@@ -208,7 +215,7 @@ fn check_final_expr<'tcx>(
208
215
expr : & ' tcx Expr < ' tcx > ,
209
216
semi_spans : Vec < Span > , /* containing all the places where we would need to remove semicolons if finding an
210
217
* needless return */
211
- replacement : RetReplacement ,
218
+ replacement : RetReplacement < ' tcx > ,
212
219
) {
213
220
let peeled_drop_expr = expr. peel_drop_temps ( ) ;
214
221
match & peeled_drop_expr. kind {
@@ -229,17 +236,12 @@ fn check_final_expr<'tcx>(
229
236
return ;
230
237
}
231
238
232
- let ( snippet, _) = snippet_with_context (
233
- cx,
234
- inner_expr. span ,
235
- ret_span. ctxt ( ) ,
236
- ".." ,
237
- & mut Applicability :: MachineApplicable ,
238
- ) ;
239
- if expr_contains_if ( inner_expr) {
240
- RetReplacement :: IfSequence ( snippet. to_string ( ) )
239
+ let mut applicability = Applicability :: MachineApplicable ;
240
+ let ( snippet, _) = snippet_with_context ( cx, inner_expr. span , ret_span. ctxt ( ) , ".." , & mut applicability) ;
241
+ if expr_contains_conjunctive_ifs ( inner_expr) {
242
+ RetReplacement :: IfSequence ( snippet, applicability)
241
243
} else {
242
- RetReplacement :: Expr ( snippet. to_string ( ) )
244
+ RetReplacement :: Expr ( snippet, applicability )
243
245
}
244
246
} else {
245
247
replacement
@@ -275,19 +277,23 @@ fn check_final_expr<'tcx>(
275
277
}
276
278
}
277
279
278
- fn expr_contains_if < ' tcx > ( expr : & ' tcx Expr < ' tcx > ) -> bool {
279
- match expr. kind {
280
- ExprKind :: If ( ..) => true ,
281
- ExprKind :: Binary ( _, left, right) => expr_contains_if ( left) || expr_contains_if ( right) ,
282
- _ => false ,
280
+ fn expr_contains_conjunctive_ifs < ' tcx > ( expr : & ' tcx Expr < ' tcx > ) -> bool {
281
+ fn contains_if ( expr : & Expr < ' _ > , on_if : bool ) -> bool {
282
+ match expr. kind {
283
+ ExprKind :: If ( ..) => on_if,
284
+ ExprKind :: Binary ( _, left, right) => contains_if ( left, true ) || contains_if ( right, true ) ,
285
+ _ => false ,
286
+ }
283
287
}
288
+
289
+ contains_if ( expr, false )
284
290
}
285
291
286
- fn emit_return_lint ( cx : & LateContext < ' _ > , ret_span : Span , semi_spans : Vec < Span > , replacement : RetReplacement ) {
292
+ fn emit_return_lint ( cx : & LateContext < ' _ > , ret_span : Span , semi_spans : Vec < Span > , replacement : RetReplacement < ' _ > ) {
287
293
if ret_span. from_expansion ( ) {
288
294
return ;
289
295
}
290
- let applicability = Applicability :: MachineApplicable ;
296
+ let applicability = replacement . applicability ( ) . unwrap_or ( Applicability :: MachineApplicable ) ;
291
297
let return_replacement = replacement. to_string ( ) ;
292
298
let sugg_help = replacement. sugg_help ( ) ;
293
299
span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded `return` statement" , |diag| {
0 commit comments