@@ -14,6 +14,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
1414use rustc_span:: def_id:: LocalDefId ;
1515use rustc_span:: source_map:: Span ;
1616use rustc_span:: { BytePos , Pos } ;
17+ use std:: borrow:: Cow ;
1718
1819declare_clippy_lint ! {
1920 /// ### What it does
@@ -70,33 +71,39 @@ declare_clippy_lint! {
7071}
7172
7273#[ derive( PartialEq , Eq , Clone ) ]
73- enum RetReplacement {
74+ enum RetReplacement < ' tcx > {
7475 Empty ,
7576 Block ,
7677 Unit ,
77- IfSequence ( String ) ,
78- Expr ( String ) ,
78+ IfSequence ( Cow < ' tcx , str > , Applicability ) ,
79+ Expr ( Cow < ' tcx , str > , Applicability ) ,
7980}
8081
81- impl RetReplacement {
82+ impl < ' tcx > RetReplacement < ' tcx > {
8283 fn sugg_help ( self ) -> & ' static str {
8384 match self {
84- Self :: Empty | Self :: Expr ( _ ) => "remove `return`" ,
85+ Self :: Empty | Self :: Expr ( .. ) => "remove `return`" ,
8586 Self :: Block => "replace `return` with an empty block" ,
8687 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 ,
8895 }
8996 }
9097}
9198
92- impl ToString for RetReplacement {
99+ impl < ' tcx > ToString for RetReplacement < ' tcx > {
93100 fn to_string ( & self ) -> String {
94101 match self {
95102 Self :: Empty => String :: new ( ) ,
96103 Self :: Block => "{}" . to_string ( ) ,
97104 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 ( ) ,
100107 }
101108 }
102109}
@@ -208,7 +215,7 @@ fn check_final_expr<'tcx>(
208215 expr : & ' tcx Expr < ' tcx > ,
209216 semi_spans : Vec < Span > , /* containing all the places where we would need to remove semicolons if finding an
210217 * needless return */
211- replacement : RetReplacement ,
218+ replacement : RetReplacement < ' tcx > ,
212219) {
213220 let peeled_drop_expr = expr. peel_drop_temps ( ) ;
214221 match & peeled_drop_expr. kind {
@@ -229,17 +236,12 @@ fn check_final_expr<'tcx>(
229236 return ;
230237 }
231238
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)
241243 } else {
242- RetReplacement :: Expr ( snippet. to_string ( ) )
244+ RetReplacement :: Expr ( snippet, applicability )
243245 }
244246 } else {
245247 replacement
@@ -275,19 +277,23 @@ fn check_final_expr<'tcx>(
275277 }
276278}
277279
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+ }
283287 }
288+
289+ contains_if ( expr, false )
284290}
285291
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 < ' _ > ) {
287293 if ret_span. from_expansion ( ) {
288294 return ;
289295 }
290- let applicability = Applicability :: MachineApplicable ;
296+ let applicability = replacement . applicability ( ) . unwrap_or ( Applicability :: MachineApplicable ) ;
291297 let return_replacement = replacement. to_string ( ) ;
292298 let sugg_help = replacement. sugg_help ( ) ;
293299 span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded `return` statement" , |diag| {
0 commit comments