1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
2
use clippy_utils:: macros:: HirNode ;
3
- use clippy_utils:: source:: { indent_of, snippet, snippet_block_with_context, snippet_with_context} ;
3
+ use clippy_utils:: source:: {
4
+ indent_of, reindent_multiline_relative, snippet, snippet_block_with_context, snippet_with_context,
5
+ } ;
4
6
use clippy_utils:: { is_refutable, peel_blocks} ;
5
7
use rustc_errors:: Applicability ;
6
8
use rustc_hir:: { Arm , Expr , ExprKind , Node , PatKind , StmtKind } ;
@@ -50,7 +52,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
50
52
cx,
51
53
( ex, expr) ,
52
54
( bind_names, matched_vars) ,
53
- & snippet_body,
55
+ snippet_body,
54
56
& mut app,
55
57
Some ( span) ,
56
58
true ,
@@ -83,7 +85,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
83
85
cx,
84
86
( ex, expr) ,
85
87
( bind_names, matched_vars) ,
86
- & snippet_body,
88
+ snippet_body,
87
89
& mut app,
88
90
None ,
89
91
true ,
@@ -108,7 +110,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
108
110
cx,
109
111
( ex, expr) ,
110
112
( bind_names, matched_vars) ,
111
- & snippet_body,
113
+ snippet_body,
112
114
& mut app,
113
115
None ,
114
116
false ,
@@ -161,47 +163,56 @@ fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<Ass
161
163
None
162
164
}
163
165
164
- fn expr_parent_requires_curlies < ' a > ( cx : & LateContext < ' a > , match_expr : & Expr < ' a > ) -> bool {
166
+ fn expr_in_nested_block ( cx : & LateContext < ' _ > , match_expr : & Expr < ' _ > ) -> bool {
167
+ if let Node :: Block ( block) = cx. tcx . parent_hir_node ( match_expr. hir_id ) {
168
+ return block
169
+ . expr
170
+ . map_or_else ( || matches ! ( block. stmts, [ _] ) , |_| block. stmts . is_empty ( ) ) ;
171
+ }
172
+ false
173
+ }
174
+
175
+ fn expr_must_have_curlies ( cx : & LateContext < ' _ > , match_expr : & Expr < ' _ > ) -> bool {
165
176
let parent = cx. tcx . parent_hir_node ( match_expr. hir_id ) ;
166
- matches ! (
167
- parent,
168
- Node :: Expr ( Expr {
169
- kind: ExprKind :: Closure { .. } ,
170
- ..
171
- } ) | Node :: AnonConst ( ..)
177
+ if let Node :: Expr ( Expr {
178
+ kind : ExprKind :: Closure { .. } ,
179
+ ..
180
+ } )
181
+ | Node :: AnonConst ( ..) = parent
182
+ {
183
+ return true ;
184
+ }
185
+
186
+ if let Node :: Arm ( arm) = & cx. tcx . parent_hir_node ( match_expr. hir_id )
187
+ && let ExprKind :: Match ( ..) = arm. body . kind
188
+ {
189
+ return true ;
190
+ }
191
+
192
+ false
193
+ }
194
+
195
+ fn reindent_snippet_if_in_block ( snippet_body : & str , has_assignment : bool ) -> String {
196
+ if has_assignment || !snippet_body. starts_with ( '{' ) {
197
+ return reindent_multiline_relative ( snippet_body, true , 0 ) ;
198
+ }
199
+
200
+ reindent_multiline_relative (
201
+ snippet_body. trim_start_matches ( '{' ) . trim_end_matches ( '}' ) . trim ( ) ,
202
+ false ,
203
+ -4 ,
172
204
)
173
205
}
174
206
175
207
fn sugg_with_curlies < ' a > (
176
208
cx : & LateContext < ' a > ,
177
209
( ex, match_expr) : ( & Expr < ' a > , & Expr < ' a > ) ,
178
210
( bind_names, matched_vars) : ( Span , Span ) ,
179
- snippet_body : & str ,
211
+ mut snippet_body : String ,
180
212
applicability : & mut Applicability ,
181
213
assignment : Option < Span > ,
182
214
needs_var_binding : bool ,
183
215
) -> String {
184
- let mut indent = " " . repeat ( indent_of ( cx, ex. span ) . unwrap_or ( 0 ) ) ;
185
-
186
- let ( mut cbrace_start, mut cbrace_end) = ( String :: new ( ) , String :: new ( ) ) ;
187
- if expr_parent_requires_curlies ( cx, match_expr) {
188
- cbrace_end = format ! ( "\n {indent}}}" ) ;
189
- // Fix body indent due to the closure
190
- indent = " " . repeat ( indent_of ( cx, bind_names) . unwrap_or ( 0 ) ) ;
191
- cbrace_start = format ! ( "{{\n {indent}" ) ;
192
- }
193
-
194
- // If the parent is already an arm, and the body is another match statement,
195
- // we need curly braces around suggestion
196
- if let Node :: Arm ( arm) = & cx. tcx . parent_hir_node ( match_expr. hir_id )
197
- && let ExprKind :: Match ( ..) = arm. body . kind
198
- {
199
- cbrace_end = format ! ( "\n {indent}}}" ) ;
200
- // Fix body indent due to the match
201
- indent = " " . repeat ( indent_of ( cx, bind_names) . unwrap_or ( 0 ) ) ;
202
- cbrace_start = format ! ( "{{\n {indent}" ) ;
203
- }
204
-
205
216
let assignment_str = assignment. map_or_else ( String :: new, |span| {
206
217
let mut s = snippet ( cx, span, ".." ) . to_string ( ) ;
207
218
s. push_str ( " = " ) ;
@@ -221,5 +232,15 @@ fn sugg_with_curlies<'a>(
221
232
. to_string ( )
222
233
} ;
223
234
235
+ let mut indent = " " . repeat ( indent_of ( cx, ex. span ) . unwrap_or ( 0 ) ) ;
236
+ let ( mut cbrace_start, mut cbrace_end) = ( String :: new ( ) , String :: new ( ) ) ;
237
+ if !expr_in_nested_block ( cx, match_expr) && ( needs_var_binding || expr_must_have_curlies ( cx, match_expr) ) {
238
+ cbrace_end = format ! ( "\n {indent}}}" ) ;
239
+ // Fix body indent due to the closure
240
+ indent = " " . repeat ( indent_of ( cx, bind_names) . unwrap_or ( 0 ) ) ;
241
+ cbrace_start = format ! ( "{{\n {indent}" ) ;
242
+ snippet_body = reindent_snippet_if_in_block ( & snippet_body, !assignment_str. is_empty ( ) ) ;
243
+ }
244
+
224
245
format ! ( "{cbrace_start}{scrutinee};\n {indent}{assignment_str}{snippet_body}{cbrace_end}" )
225
246
}
0 commit comments