Add wild and struct handling

This commit is contained in:
ThibsG 2020-01-26 17:03:39 +01:00
parent 6afd7ea147
commit b29aacfec8
7 changed files with 272 additions and 36 deletions

View File

@ -3,9 +3,9 @@ use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::usage::is_unused;
use crate::utils::{
span_lint_and_help, span_lint_and_note,
expr_block, in_macro, is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks,
snippet, snippet_block, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
expr_block, get_arg_name, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, match_type,
match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help,
span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
@ -822,36 +822,66 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
}
fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if in_macro(expr.span) {
if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
return;
}
if arms.len() == 1 {
if is_refutable(cx, arms[0].pat) {
return;
}
match arms[0].pat.kind {
PatKind::Binding(..) | PatKind::Tuple(_, _) => {
let bind_names = arms[0].pat.span;
let matched_vars = ex.span;
let match_body = remove_blocks(&arms[0].body);
span_lint_and_sugg(
cx,
MATCH_SINGLE_BINDING,
expr.span,
"this match could be written as a `let` statement",
"consider using `let` statement",
format!(
"let {} = {};\n{}",
snippet(cx, bind_names, ".."),
snippet(cx, matched_vars, ".."),
snippet_block(cx, match_body.span, "..")
),
Applicability::MachineApplicable,
);
},
_ => (),
let matched_vars = ex.span;
let bind_names = arms[0].pat.span;
let match_body = remove_blocks(&arms[0].body);
let mut snippet_body = if match_body.span.from_expansion() {
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
} else {
snippet_block(cx, match_body.span, "..").to_owned().to_string()
};
// Do we need to add ';' to suggestion ?
if_chain! {
if let ExprKind::Block(block, _) = &arms[0].body.kind;
if block.stmts.len() == 1;
if let StmtKind::Semi(s) = block.stmts.get(0).unwrap().kind;
then {
match s.kind {
ExprKind::Block(_, _) => (),
_ => {
// expr_ty(body) == ()
if cx.tables.expr_ty(&arms[0].body).is_unit() {
snippet_body.push(';');
}
}
}
}
}
match arms[0].pat.kind {
PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
span_lint_and_sugg(
cx,
MATCH_SINGLE_BINDING,
expr.span,
"this match could be written as a `let` statement",
"consider using `let` statement",
format!(
"let {} = {};\n{}",
snippet(cx, bind_names, ".."),
snippet(cx, matched_vars, ".."),
snippet_body
),
Applicability::MachineApplicable,
);
},
PatKind::Wild => {
span_lint_and_sugg(
cx,
MATCH_SINGLE_BINDING,
expr.span,
"this match could be replaced by its body itself",
"consider using the match body instead",
snippet_body,
Applicability::MachineApplicable,
);
},
_ => (),
}
}
/// Gets all arms that are unbounded `PatRange`s.

View File

@ -4,6 +4,7 @@
clippy::needless_pass_by_value,
clippy::unused_unit,
clippy::redundant_clone,
clippy::match_single_binding
)]
#![warn(clippy::boxed_local)]

View File

@ -26,6 +26,7 @@ fn ref_pats() {
}
// False positive: only wildcard pattern.
let w = Some(0);
#[allow(clippy::match_single_binding)]
match w {
_ => println!("none"),
}

View File

@ -47,7 +47,7 @@ LL | None => println!("none"),
|
error: you don't need to add `&` to all patterns
--> $DIR/match_ref_pats.rs:34:5
--> $DIR/match_ref_pats.rs:35:5
|
LL | / if let &None = a {
LL | | println!("none");
@ -60,7 +60,7 @@ LL | if let None = *a {
| ^^^^ ^^
error: you don't need to add `&` to both the expression and the patterns
--> $DIR/match_ref_pats.rs:39:5
--> $DIR/match_ref_pats.rs:40:5
|
LL | / if let &None = &b {
LL | | println!("none");
@ -73,7 +73,7 @@ LL | if let None = b {
| ^^^^ ^
error: you don't need to add `&` to all patterns
--> $DIR/match_ref_pats.rs:66:9
--> $DIR/match_ref_pats.rs:67:9
|
LL | / match foo_variant!(0) {
LL | | &Foo::A => println!("A"),

View File

@ -1,7 +1,12 @@
// run-rustfix
#![warn(clippy::match_single_binding)]
#[allow(clippy::many_single_char_names)]
#![allow(clippy::many_single_char_names, clippy::toplevel_ref_arg)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let a = 1;
@ -12,6 +17,9 @@ fn main() {
{
println!("{} {} {}", x, y, z);
}
// Lint
let (x, y, z) = (a, b, c);
println!("{} {} {}", x, y, z);
// Ok
match a {
2 => println!("2"),
@ -23,4 +31,33 @@ fn main() {
Some(d) => println!("{}", d),
_ => println!("None"),
}
// Lint
println!("whatever");
// Lint
{
let x = 29;
println!("x has a value of {}", x);
}
// Lint
{
let e = 5 * a;
if e >= 5 {
println!("e is superior to 5");
}
}
// Lint
let p = Point { x: 0, y: 7 };
let Point { x, y } = p;
println!("Coords: ({}, {})", x, y);
// Lint
let Point { x: x1, y: y1 } = p;
println!("Coords: ({}, {})", x1, y1);
// Lint
let x = 5;
let ref r = x;
println!("Got a reference to {}", r);
// Lint
let mut x = 5;
let ref mut mr = x;
println!("Got a mutable reference to {}", mr);
}

View File

@ -1,7 +1,12 @@
// run-rustfix
#![warn(clippy::match_single_binding)]
#[allow(clippy::many_single_char_names)]
#![allow(clippy::many_single_char_names, clippy::toplevel_ref_arg)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let a = 1;
@ -13,6 +18,10 @@ fn main() {
println!("{} {} {}", x, y, z);
},
}
// Lint
match (a, b, c) {
(x, y, z) => println!("{} {} {}", x, y, z),
}
// Ok
match a {
2 => println!("2"),
@ -24,4 +33,43 @@ fn main() {
Some(d) => println!("{}", d),
_ => println!("None"),
}
// Lint
match a {
_ => println!("whatever"),
}
// Lint
match a {
_ => {
let x = 29;
println!("x has a value of {}", x);
},
}
// Lint
match a {
_ => {
let e = 5 * a;
if e >= 5 {
println!("e is superior to 5");
}
},
}
// Lint
let p = Point { x: 0, y: 7 };
match p {
Point { x, y } => println!("Coords: ({}, {})", x, y),
}
// Lint
match p {
Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
}
// Lint
let x = 5;
match x {
ref r => println!("Got a reference to {}", r),
}
// Lint
let mut x = 5;
match x {
ref mut mr => println!("Got a mutable reference to {}", mr),
}
}

View File

@ -1,5 +1,5 @@
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:11:5
--> $DIR/match_single_binding.rs:16:5
|
LL | / match (a, b, c) {
LL | | (x, y, z) => {
@ -17,5 +17,124 @@ LL | println!("{} {} {}", x, y, z);
LL | }
|
error: aborting due to previous error
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:22:5
|
LL | / match (a, b, c) {
LL | | (x, y, z) => println!("{} {} {}", x, y, z),
LL | | }
| |_____^
|
help: consider using `let` statement
|
LL | let (x, y, z) = (a, b, c);
LL | println!("{} {} {}", x, y, z);
|
error: this match could be replaced by its body itself
--> $DIR/match_single_binding.rs:37:5
|
LL | / match a {
LL | | _ => println!("whatever"),
LL | | }
| |_____^ help: consider using the match body instead: `println!("whatever");`
error: this match could be replaced by its body itself
--> $DIR/match_single_binding.rs:41:5
|
LL | / match a {
LL | | _ => {
LL | | let x = 29;
LL | | println!("x has a value of {}", x);
LL | | },
LL | | }
| |_____^
|
help: consider using the match body instead
|
LL | {
LL | let x = 29;
LL | println!("x has a value of {}", x);
LL | }
|
error: this match could be replaced by its body itself
--> $DIR/match_single_binding.rs:48:5
|
LL | / match a {
LL | | _ => {
LL | | let e = 5 * a;
LL | | if e >= 5 {
... |
LL | | },
LL | | }
| |_____^
|
help: consider using the match body instead
|
LL | {
LL | let e = 5 * a;
LL | if e >= 5 {
LL | println!("e is superior to 5");
LL | }
LL | }
|
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:58:5
|
LL | / match p {
LL | | Point { x, y } => println!("Coords: ({}, {})", x, y),
LL | | }
| |_____^
|
help: consider using `let` statement
|
LL | let Point { x, y } = p;
LL | println!("Coords: ({}, {})", x, y);
|
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:62:5
|
LL | / match p {
LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
LL | | }
| |_____^
|
help: consider using `let` statement
|
LL | let Point { x: x1, y: y1 } = p;
LL | println!("Coords: ({}, {})", x1, y1);
|
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:67:5
|
LL | / match x {
LL | | ref r => println!("Got a reference to {}", r),
LL | | }
| |_____^
|
help: consider using `let` statement
|
LL | let ref r = x;
LL | println!("Got a reference to {}", r);
|
error: this match could be written as a `let` statement
--> $DIR/match_single_binding.rs:72:5
|
LL | / match x {
LL | | ref mut mr => println!("Got a mutable reference to {}", mr),
LL | | }
| |_____^
|
help: consider using `let` statement
|
LL | let ref mut mr = x;
LL | println!("Got a mutable reference to {}", mr);
|
error: aborting due to 9 previous errors