Skip to content

Commit f39ed7a

Browse files
committed
fix: match_single_binding suggests wrongly inside tuple
1 parent 99b8106 commit f39ed7a

File tree

4 files changed

+348
-24
lines changed

4 files changed

+348
-24
lines changed

clippy_lints/src/matches/match_single_binding.rs

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -307,26 +307,6 @@ fn expr_in_nested_block(cx: &LateContext<'_>, match_expr: &Expr<'_>) -> bool {
307307
false
308308
}
309309

310-
fn expr_must_have_curlies(cx: &LateContext<'_>, match_expr: &Expr<'_>) -> bool {
311-
let parent = cx.tcx.parent_hir_node(match_expr.hir_id);
312-
if let Node::Expr(Expr {
313-
kind: ExprKind::Closure(..) | ExprKind::Binary(..),
314-
..
315-
})
316-
| Node::AnonConst(..) = parent
317-
{
318-
return true;
319-
}
320-
321-
if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id)
322-
&& let ExprKind::Match(..) = arm.body.kind
323-
{
324-
return true;
325-
}
326-
327-
false
328-
}
329-
330310
fn indent_of_nth_line(snippet: &str, nth: usize) -> Option<usize> {
331311
snippet
332312
.lines()
@@ -379,14 +359,42 @@ fn sugg_with_curlies<'a>(
379359

380360
let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
381361
let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new());
382-
if !expr_in_nested_block(cx, match_expr)
383-
&& ((needs_var_binding && is_var_binding_used_later) || expr_must_have_curlies(cx, match_expr))
384-
{
362+
let mut add_curlies = || {
385363
cbrace_end = format!("\n{indent}}}");
386364
// Fix body indent due to the closure
387365
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
388366
cbrace_start = format!("{{\n{indent}");
389367
snippet_body = reindent_snippet_if_in_block(&snippet_body, !assignment_str.is_empty());
368+
};
369+
370+
if !expr_in_nested_block(cx, match_expr) {
371+
let mut parent = cx.tcx.parent_hir_node(match_expr.hir_id);
372+
if let Node::Expr(Expr {
373+
kind: ExprKind::Assign(..),
374+
hir_id,
375+
..
376+
}) = parent
377+
{
378+
parent = cx.tcx.parent_hir_node(*hir_id);
379+
}
380+
if let Node::Stmt(stmt) = parent {
381+
parent = cx.tcx.parent_hir_node(stmt.hir_id);
382+
}
383+
384+
match parent {
385+
Node::Block(..)
386+
| Node::Expr(Expr {
387+
kind: ExprKind::Block(..) | ExprKind::ConstBlock(..),
388+
..
389+
}) => {
390+
if needs_var_binding && is_var_binding_used_later {
391+
add_curlies();
392+
}
393+
},
394+
Node::Expr(..) | Node::AnonConst(..) => add_curlies(),
395+
Node::Arm(arm) if let ExprKind::Match(..) = arm.body.kind => add_curlies(),
396+
_ => {},
397+
}
390398
}
391399

392400
format!("{cbrace_start}{scrutinee};\n{indent}{assignment_str}{snippet_body}{cbrace_end}")

tests/ui/match_single_binding.fixed

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,82 @@ fn issue15269(a: usize, b: usize, c: usize) -> bool {
265265
a < b
266266
&& b < c
267267
}
268+
269+
#[allow(
270+
irrefutable_let_patterns,
271+
clippy::blocks_in_conditions,
272+
clippy::unused_unit,
273+
clippy::let_unit_value,
274+
clippy::unit_arg,
275+
clippy::unnecessary_operation
276+
)]
277+
fn issue15537(a: i32) -> ((), (), ()) {
278+
let y = (
279+
{ todo!() },
280+
{
281+
{ a };
282+
()
283+
},
284+
(),
285+
);
286+
287+
let y = [
288+
{ todo!() },
289+
{
290+
{ a };
291+
()
292+
},
293+
(),
294+
];
295+
296+
fn call(x: (), y: (), z: ()) {}
297+
let y = call(
298+
{ todo!() },
299+
{
300+
{ a };
301+
()
302+
},
303+
(),
304+
);
305+
306+
struct Foo;
307+
impl Foo {
308+
fn method(&self, x: (), y: (), z: ()) {}
309+
}
310+
let x = Foo;
311+
x.method(
312+
{ todo!() },
313+
{
314+
{ a };
315+
()
316+
},
317+
(),
318+
);
319+
320+
-{
321+
{ a };
322+
1
323+
};
324+
325+
_ = { a };
326+
1;
327+
328+
if let x = {
329+
{ a };
330+
1
331+
} {}
332+
333+
if {
334+
{ a };
335+
true
336+
} {
337+
todo!()
338+
}
339+
340+
[1, 2, 3][{
341+
{ a };
342+
1usize
343+
}];
344+
345+
todo!()
346+
}

tests/ui/match_single_binding.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,84 @@ fn issue15269(a: usize, b: usize, c: usize) -> bool {
342342
(a, b) => b < c,
343343
}
344344
}
345+
346+
#[allow(
347+
irrefutable_let_patterns,
348+
clippy::blocks_in_conditions,
349+
clippy::unused_unit,
350+
clippy::let_unit_value,
351+
clippy::unit_arg,
352+
clippy::unnecessary_operation
353+
)]
354+
fn issue15537(a: i32) -> ((), (), ()) {
355+
let y = (
356+
{ todo!() },
357+
match { a } {
358+
//~^ match_single_binding
359+
_ => (),
360+
},
361+
(),
362+
);
363+
364+
let y = [
365+
{ todo!() },
366+
match { a } {
367+
//~^ match_single_binding
368+
_ => (),
369+
},
370+
(),
371+
];
372+
373+
fn call(x: (), y: (), z: ()) {}
374+
let y = call(
375+
{ todo!() },
376+
match { a } {
377+
//~^ match_single_binding
378+
_ => (),
379+
},
380+
(),
381+
);
382+
383+
struct Foo;
384+
impl Foo {
385+
fn method(&self, x: (), y: (), z: ()) {}
386+
}
387+
let x = Foo;
388+
x.method(
389+
{ todo!() },
390+
match { a } {
391+
//~^ match_single_binding
392+
_ => (),
393+
},
394+
(),
395+
);
396+
397+
-match { a } {
398+
//~^ match_single_binding
399+
_ => 1,
400+
};
401+
402+
_ = match { a } {
403+
//~^ match_single_binding
404+
_ => 1,
405+
};
406+
407+
if let x = match { a } {
408+
//~^ match_single_binding
409+
_ => 1,
410+
} {}
411+
412+
if match { a } {
413+
//~^ match_single_binding
414+
_ => true,
415+
} {
416+
todo!()
417+
}
418+
419+
[1, 2, 3][match { a } {
420+
//~^ match_single_binding
421+
_ => 1usize,
422+
}];
423+
424+
todo!()
425+
}

0 commit comments

Comments
 (0)