Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit b29aacf

Browse files
committed
Add wild and struct handling
1 parent 6afd7ea commit b29aacf

File tree

7 files changed

+272
-36
lines changed

7 files changed

+272
-36
lines changed

clippy_lints/src/matches.rs

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use crate::utils::paths;
33
use crate::utils::sugg::Sugg;
44
use crate::utils::usage::is_unused;
55
use crate::utils::{
6-
span_lint_and_help, span_lint_and_note,
7-
expr_block, in_macro, is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks,
8-
snippet, snippet_block, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
6+
expr_block, get_arg_name, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, match_type,
7+
match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help,
8+
span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
99
};
1010
use if_chain::if_chain;
1111
use rustc::lint::in_external_macro;
@@ -822,36 +822,66 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
822822
}
823823

824824
fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
825-
if in_macro(expr.span) {
825+
if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
826826
return;
827827
}
828-
if arms.len() == 1 {
829-
if is_refutable(cx, arms[0].pat) {
830-
return;
831-
}
832-
match arms[0].pat.kind {
833-
PatKind::Binding(..) | PatKind::Tuple(_, _) => {
834-
let bind_names = arms[0].pat.span;
835-
let matched_vars = ex.span;
836-
let match_body = remove_blocks(&arms[0].body);
837-
span_lint_and_sugg(
838-
cx,
839-
MATCH_SINGLE_BINDING,
840-
expr.span,
841-
"this match could be written as a `let` statement",
842-
"consider using `let` statement",
843-
format!(
844-
"let {} = {};\n{}",
845-
snippet(cx, bind_names, ".."),
846-
snippet(cx, matched_vars, ".."),
847-
snippet_block(cx, match_body.span, "..")
848-
),
849-
Applicability::MachineApplicable,
850-
);
851-
},
852-
_ => (),
828+
let matched_vars = ex.span;
829+
let bind_names = arms[0].pat.span;
830+
let match_body = remove_blocks(&arms[0].body);
831+
let mut snippet_body = if match_body.span.from_expansion() {
832+
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
833+
} else {
834+
snippet_block(cx, match_body.span, "..").to_owned().to_string()
835+
};
836+
837+
// Do we need to add ';' to suggestion ?
838+
if_chain! {
839+
if let ExprKind::Block(block, _) = &arms[0].body.kind;
840+
if block.stmts.len() == 1;
841+
if let StmtKind::Semi(s) = block.stmts.get(0).unwrap().kind;
842+
then {
843+
match s.kind {
844+
ExprKind::Block(_, _) => (),
845+
_ => {
846+
// expr_ty(body) == ()
847+
if cx.tables.expr_ty(&arms[0].body).is_unit() {
848+
snippet_body.push(';');
849+
}
850+
}
851+
}
853852
}
854853
}
854+
855+
match arms[0].pat.kind {
856+
PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
857+
span_lint_and_sugg(
858+
cx,
859+
MATCH_SINGLE_BINDING,
860+
expr.span,
861+
"this match could be written as a `let` statement",
862+
"consider using `let` statement",
863+
format!(
864+
"let {} = {};\n{}",
865+
snippet(cx, bind_names, ".."),
866+
snippet(cx, matched_vars, ".."),
867+
snippet_body
868+
),
869+
Applicability::MachineApplicable,
870+
);
871+
},
872+
PatKind::Wild => {
873+
span_lint_and_sugg(
874+
cx,
875+
MATCH_SINGLE_BINDING,
876+
expr.span,
877+
"this match could be replaced by its body itself",
878+
"consider using the match body instead",
879+
snippet_body,
880+
Applicability::MachineApplicable,
881+
);
882+
},
883+
_ => (),
884+
}
855885
}
856886

857887
/// Gets all arms that are unbounded `PatRange`s.

tests/ui/escape_analysis.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
clippy::needless_pass_by_value,
55
clippy::unused_unit,
66
clippy::redundant_clone,
7+
clippy::match_single_binding
78
)]
89
#![warn(clippy::boxed_local)]
910

tests/ui/match_ref_pats.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ fn ref_pats() {
2626
}
2727
// False positive: only wildcard pattern.
2828
let w = Some(0);
29+
#[allow(clippy::match_single_binding)]
2930
match w {
3031
_ => println!("none"),
3132
}

tests/ui/match_ref_pats.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ LL | None => println!("none"),
4747
|
4848

4949
error: you don't need to add `&` to all patterns
50-
--> $DIR/match_ref_pats.rs:34:5
50+
--> $DIR/match_ref_pats.rs:35:5
5151
|
5252
LL | / if let &None = a {
5353
LL | | println!("none");
@@ -60,7 +60,7 @@ LL | if let None = *a {
6060
| ^^^^ ^^
6161

6262
error: you don't need to add `&` to both the expression and the patterns
63-
--> $DIR/match_ref_pats.rs:39:5
63+
--> $DIR/match_ref_pats.rs:40:5
6464
|
6565
LL | / if let &None = &b {
6666
LL | | println!("none");
@@ -73,7 +73,7 @@ LL | if let None = b {
7373
| ^^^^ ^
7474

7575
error: you don't need to add `&` to all patterns
76-
--> $DIR/match_ref_pats.rs:66:9
76+
--> $DIR/match_ref_pats.rs:67:9
7777
|
7878
LL | / match foo_variant!(0) {
7979
LL | | &Foo::A => println!("A"),

tests/ui/match_single_binding.fixed

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
// run-rustfix
22

33
#![warn(clippy::match_single_binding)]
4-
#[allow(clippy::many_single_char_names)]
4+
#![allow(clippy::many_single_char_names, clippy::toplevel_ref_arg)]
5+
6+
struct Point {
7+
x: i32,
8+
y: i32,
9+
}
510

611
fn main() {
712
let a = 1;
@@ -12,6 +17,9 @@ fn main() {
1217
{
1318
println!("{} {} {}", x, y, z);
1419
}
20+
// Lint
21+
let (x, y, z) = (a, b, c);
22+
println!("{} {} {}", x, y, z);
1523
// Ok
1624
match a {
1725
2 => println!("2"),
@@ -23,4 +31,33 @@ fn main() {
2331
Some(d) => println!("{}", d),
2432
_ => println!("None"),
2533
}
34+
// Lint
35+
println!("whatever");
36+
// Lint
37+
{
38+
let x = 29;
39+
println!("x has a value of {}", x);
40+
}
41+
// Lint
42+
{
43+
let e = 5 * a;
44+
if e >= 5 {
45+
println!("e is superior to 5");
46+
}
47+
}
48+
// Lint
49+
let p = Point { x: 0, y: 7 };
50+
let Point { x, y } = p;
51+
println!("Coords: ({}, {})", x, y);
52+
// Lint
53+
let Point { x: x1, y: y1 } = p;
54+
println!("Coords: ({}, {})", x1, y1);
55+
// Lint
56+
let x = 5;
57+
let ref r = x;
58+
println!("Got a reference to {}", r);
59+
// Lint
60+
let mut x = 5;
61+
let ref mut mr = x;
62+
println!("Got a mutable reference to {}", mr);
2663
}

tests/ui/match_single_binding.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
// run-rustfix
22

33
#![warn(clippy::match_single_binding)]
4-
#[allow(clippy::many_single_char_names)]
4+
#![allow(clippy::many_single_char_names, clippy::toplevel_ref_arg)]
5+
6+
struct Point {
7+
x: i32,
8+
y: i32,
9+
}
510

611
fn main() {
712
let a = 1;
@@ -13,6 +18,10 @@ fn main() {
1318
println!("{} {} {}", x, y, z);
1419
},
1520
}
21+
// Lint
22+
match (a, b, c) {
23+
(x, y, z) => println!("{} {} {}", x, y, z),
24+
}
1625
// Ok
1726
match a {
1827
2 => println!("2"),
@@ -24,4 +33,43 @@ fn main() {
2433
Some(d) => println!("{}", d),
2534
_ => println!("None"),
2635
}
36+
// Lint
37+
match a {
38+
_ => println!("whatever"),
39+
}
40+
// Lint
41+
match a {
42+
_ => {
43+
let x = 29;
44+
println!("x has a value of {}", x);
45+
},
46+
}
47+
// Lint
48+
match a {
49+
_ => {
50+
let e = 5 * a;
51+
if e >= 5 {
52+
println!("e is superior to 5");
53+
}
54+
},
55+
}
56+
// Lint
57+
let p = Point { x: 0, y: 7 };
58+
match p {
59+
Point { x, y } => println!("Coords: ({}, {})", x, y),
60+
}
61+
// Lint
62+
match p {
63+
Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
64+
}
65+
// Lint
66+
let x = 5;
67+
match x {
68+
ref r => println!("Got a reference to {}", r),
69+
}
70+
// Lint
71+
let mut x = 5;
72+
match x {
73+
ref mut mr => println!("Got a mutable reference to {}", mr),
74+
}
2775
}

0 commit comments

Comments
 (0)