quick fix of issue#8542 for lint [needless_match]

remove `ref`/`ref mut` check
This commit is contained in:
J-ZhengLi 2022-03-16 16:26:56 +08:00
parent b83c6323c7
commit 2909b33a24
4 changed files with 257 additions and 151 deletions

View File

@ -5,7 +5,7 @@
use clippy_utils::{eq_expr_value, get_parent_expr, higher, is_else_clause, is_lang_ctor, peel_blocks_with_stmt};
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, Pat, PatKind, Path, PathSegment, QPath, UnOp};
use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, Pat, PatKind, Path, PathSegment, QPath};
use rustc_lint::LateContext;
use rustc_span::sym;
@ -21,7 +21,7 @@ pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
if !eq_expr_value(cx, ex, ret_expr) {
return;
}
} else if !pat_same_as_expr(arm.pat, arm.body) {
} else if !pat_same_as_expr(arm.pat, peel_blocks_with_stmt(arm.body)) {
return;
}
}
@ -92,6 +92,9 @@ fn check_if_let(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
if matches!(if_else.kind, ExprKind::Block(..)) {
let else_expr = peel_blocks_with_stmt(if_else);
if matches!(else_expr.kind, ExprKind::Block(..)) {
return false;
}
let ret = strip_return(else_expr);
let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
@ -120,40 +123,25 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
let expr = strip_return(expr);
match (&pat.kind, &expr.kind) {
// Example: `Some(val) => Some(val)`
(
PatKind::TupleStruct(QPath::Resolved(_, path), [first_pat, ..], _),
ExprKind::Call(call_expr, [first_param, ..]),
) => {
(PatKind::TupleStruct(QPath::Resolved(_, path), tuple_params, _), ExprKind::Call(call_expr, call_params)) => {
if let ExprKind::Path(QPath::Resolved(_, call_path)) = call_expr.kind {
if has_identical_segments(path.segments, call_path.segments)
&& has_same_non_ref_symbol(first_pat, first_param)
{
return true;
}
return has_identical_segments(path.segments, call_path.segments)
&& has_same_non_ref_symbols(tuple_params, call_params);
}
},
// Example: `val => val`, or `ref val => *val`
(PatKind::Binding(annot, _, pat_ident, _), _) => {
let new_expr = if let (
BindingAnnotation::Ref | BindingAnnotation::RefMut,
ExprKind::Unary(UnOp::Deref, operand_expr),
) = (annot, &expr.kind)
{
operand_expr
} else {
expr
};
if let ExprKind::Path(QPath::Resolved(
// Example: `val => val`
(
PatKind::Binding(annot, _, pat_ident, _),
ExprKind::Path(QPath::Resolved(
_,
Path {
segments: [first_seg, ..],
..
},
)) = new_expr.kind
{
return pat_ident.name == first_seg.ident.name;
}
)),
) => {
return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
&& pat_ident.name == first_seg.ident.name;
},
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
(PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
@ -183,15 +171,16 @@ fn has_identical_segments(left_segs: &[PathSegment<'_>], right_segs: &[PathSegme
true
}
fn has_same_non_ref_symbol(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
if_chain! {
if let PatKind::Binding(annot, _, pat_ident, _) = pat.kind;
if !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
if let ExprKind::Path(QPath::Resolved(_, Path {segments: [first_seg, ..], .. })) = expr.kind;
then {
return pat_ident.name == first_seg.ident.name;
fn has_same_non_ref_symbols(pats: &[Pat<'_>], exprs: &[Expr<'_>]) -> bool {
if pats.len() != exprs.len() {
return false;
}
for i in 0..pats.len() {
if !pat_same_as_expr(&pats[i], &exprs[i]) {
return false;
}
}
false
true
}

View File

@ -4,38 +4,35 @@
#![allow(dead_code)]
#[derive(Clone, Copy)]
enum Choice {
enum Simple {
A,
B,
C,
D,
}
#[allow(unused_mut)]
fn useless_match() {
let mut i = 10;
let i = 10;
let _: i32 = i;
let _: i32 = i;
let mut _i_mut = i;
let s = "test";
let _: &str = s;
}
fn custom_type_match(se: Choice) {
let _: Choice = se;
fn custom_type_match() {
let se = Simple::A;
let _: Simple = se;
// Don't trigger
let _: Choice = match se {
Choice::A => Choice::A,
Choice::B => Choice::B,
_ => Choice::C,
let _: Simple = match se {
Simple::A => Simple::A,
Simple::B => Simple::B,
_ => Simple::C,
};
// Mingled, don't trigger
let _: Choice = match se {
Choice::A => Choice::B,
Choice::B => Choice::C,
Choice::C => Choice::D,
Choice::D => Choice::A,
let _: Simple = match se {
Simple::A => Simple::B,
Simple::B => Simple::C,
Simple::C => Simple::D,
Simple::D => Simple::A,
};
}
@ -55,29 +52,96 @@ fn func_ret_err<T>(err: T) -> Result<i32, T> {
fn result_match() {
let _: Result<i32, i32> = Ok(1);
let _: Result<i32, i32> = func_ret_err(0_i32);
// as ref, don't trigger
let res = &func_ret_err(0_i32);
let _: Result<&i32, &i32> = match *res {
Ok(ref x) => Ok(x),
Err(ref x) => Err(x),
};
}
fn if_let_option() -> Option<i32> {
Some(1)
}
fn if_let_result(x: Result<(), i32>) {
let _: Result<(), i32> = x;
let _: Result<(), i32> = x;
fn if_let_result() {
let x: Result<i32, i32> = Ok(1);
let _: Result<i32, i32> = x;
let _: Result<i32, i32> = x;
// Input type mismatch, don't trigger
let _: Result<(), i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
let _: Result<i32, i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
}
fn if_let_custom_enum(x: Choice) {
let _: Choice = x;
fn if_let_custom_enum(x: Simple) {
let _: Simple = x;
// Don't trigger
let _: Choice = if let Choice::A = x {
Choice::A
let _: Simple = if let Simple::A = x {
Simple::A
} else if true {
Choice::B
Simple::B
} else {
x
};
}
mod issue8542 {
#[derive(Clone, Copy)]
enum E {
VariantA(u8, u8),
VariantB(u8, bool),
}
enum Complex {
A(u8),
B(u8, bool),
C(u8, i32, f64),
D(E, bool),
}
fn match_test() {
let ce = Complex::B(8, false);
let aa = 0_u8;
let bb = false;
let _: Complex = ce;
// Don't trigger
let _: Complex = match ce {
Complex::A(_) => Complex::A(aa),
Complex::B(_, b) => Complex::B(aa, b),
Complex::C(_, b, _) => Complex::C(aa, b, 64_f64),
Complex::D(e, b) => Complex::D(e, b),
};
// Don't trigger
let _: Complex = match ce {
Complex::A(a) => Complex::A(a),
Complex::B(a, _) => Complex::B(a, bb),
Complex::C(a, _, _) => Complex::C(a, 32_i32, 64_f64),
_ => ce,
};
}
fn if_let_test() {
fn do_something() {}
// Don't trigger
let _ = if let Some(a) = Some(1) {
Some(a)
} else {
do_something();
None
};
// Don't trigger
let _ = if let Some(a) = Some(1) {
do_something();
Some(a)
} else {
None
};
}
}
fn main() {}

View File

@ -4,33 +4,21 @@
#![allow(dead_code)]
#[derive(Clone, Copy)]
enum Choice {
enum Simple {
A,
B,
C,
D,
}
#[allow(unused_mut)]
fn useless_match() {
let mut i = 10;
let i = 10;
let _: i32 = match i {
0 => 0,
1 => 1,
2 => 2,
_ => i,
};
let _: i32 = match i {
0 => 0,
1 => 1,
ref i => *i,
};
let mut _i_mut = match i {
0 => 0,
1 => 1,
ref mut i => *i,
};
let s = "test";
let _: &str = match s {
"a" => "a",
@ -39,25 +27,26 @@ fn useless_match() {
};
}
fn custom_type_match(se: Choice) {
let _: Choice = match se {
Choice::A => Choice::A,
Choice::B => Choice::B,
Choice::C => Choice::C,
Choice::D => Choice::D,
fn custom_type_match() {
let se = Simple::A;
let _: Simple = match se {
Simple::A => Simple::A,
Simple::B => Simple::B,
Simple::C => Simple::C,
Simple::D => Simple::D,
};
// Don't trigger
let _: Choice = match se {
Choice::A => Choice::A,
Choice::B => Choice::B,
_ => Choice::C,
let _: Simple = match se {
Simple::A => Simple::A,
Simple::B => Simple::B,
_ => Simple::C,
};
// Mingled, don't trigger
let _: Choice = match se {
Choice::A => Choice::B,
Choice::B => Choice::C,
Choice::C => Choice::D,
Choice::D => Choice::A,
let _: Simple = match se {
Simple::A => Simple::B,
Simple::B => Simple::C,
Simple::C => Simple::D,
Simple::D => Simple::A,
};
}
@ -86,37 +75,110 @@ fn result_match() {
Err(err) => Err(err),
Ok(a) => Ok(a),
};
// as ref, don't trigger
let res = &func_ret_err(0_i32);
let _: Result<&i32, &i32> = match *res {
Ok(ref x) => Ok(x),
Err(ref x) => Err(x),
};
}
fn if_let_option() -> Option<i32> {
if let Some(a) = Some(1) { Some(a) } else { None }
}
fn if_let_result(x: Result<(), i32>) {
let _: Result<(), i32> = if let Err(e) = x { Err(e) } else { x };
let _: Result<(), i32> = if let Ok(val) = x { Ok(val) } else { x };
fn if_let_result() {
let x: Result<i32, i32> = Ok(1);
let _: Result<i32, i32> = if let Err(e) = x { Err(e) } else { x };
let _: Result<i32, i32> = if let Ok(val) = x { Ok(val) } else { x };
// Input type mismatch, don't trigger
let _: Result<(), i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
let _: Result<i32, i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
}
fn if_let_custom_enum(x: Choice) {
let _: Choice = if let Choice::A = x {
Choice::A
} else if let Choice::B = x {
Choice::B
} else if let Choice::C = x {
Choice::C
fn if_let_custom_enum(x: Simple) {
let _: Simple = if let Simple::A = x {
Simple::A
} else if let Simple::B = x {
Simple::B
} else if let Simple::C = x {
Simple::C
} else {
x
};
// Don't trigger
let _: Choice = if let Choice::A = x {
Choice::A
let _: Simple = if let Simple::A = x {
Simple::A
} else if true {
Choice::B
Simple::B
} else {
x
};
}
mod issue8542 {
#[derive(Clone, Copy)]
enum E {
VariantA(u8, u8),
VariantB(u8, bool),
}
enum Complex {
A(u8),
B(u8, bool),
C(u8, i32, f64),
D(E, bool),
}
fn match_test() {
let ce = Complex::B(8, false);
let aa = 0_u8;
let bb = false;
let _: Complex = match ce {
Complex::A(a) => Complex::A(a),
Complex::B(a, b) => Complex::B(a, b),
Complex::C(a, b, c) => Complex::C(a, b, c),
Complex::D(E::VariantA(ea, eb), b) => Complex::D(E::VariantA(ea, eb), b),
Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(ea, eb), b),
};
// Don't trigger
let _: Complex = match ce {
Complex::A(_) => Complex::A(aa),
Complex::B(_, b) => Complex::B(aa, b),
Complex::C(_, b, _) => Complex::C(aa, b, 64_f64),
Complex::D(e, b) => Complex::D(e, b),
};
// Don't trigger
let _: Complex = match ce {
Complex::A(a) => Complex::A(a),
Complex::B(a, _) => Complex::B(a, bb),
Complex::C(a, _, _) => Complex::C(a, 32_i32, 64_f64),
_ => ce,
};
}
fn if_let_test() {
fn do_something() {}
// Don't trigger
let _ = if let Some(a) = Some(1) {
Some(a)
} else {
do_something();
None
};
// Don't trigger
let _ = if let Some(a) = Some(1) {
do_something();
Some(a)
} else {
None
};
}
}
fn main() {}

View File

@ -1,5 +1,5 @@
error: this match expression is unnecessary
--> $DIR/needless_match.rs:17:18
--> $DIR/needless_match.rs:16:18
|
LL | let _: i32 = match i {
| __________________^
@ -13,29 +13,7 @@ LL | | };
= note: `-D clippy::needless-match` implied by `-D warnings`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:23:18
|
LL | let _: i32 = match i {
| __________________^
LL | | 0 => 0,
LL | | 1 => 1,
LL | | ref i => *i,
LL | | };
| |_____^ help: replace it with: `i`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:28:22
|
LL | let mut _i_mut = match i {
| ______________________^
LL | | 0 => 0,
LL | | 1 => 1,
LL | | ref mut i => *i,
LL | | };
| |_____^ help: replace it with: `i`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:35:19
--> $DIR/needless_match.rs:23:19
|
LL | let _: &str = match s {
| ___________________^
@ -46,19 +24,19 @@ LL | | };
| |_____^ help: replace it with: `s`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:43:21
--> $DIR/needless_match.rs:32:21
|
LL | let _: Choice = match se {
LL | let _: Simple = match se {
| _____________________^
LL | | Choice::A => Choice::A,
LL | | Choice::B => Choice::B,
LL | | Choice::C => Choice::C,
LL | | Choice::D => Choice::D,
LL | | Simple::A => Simple::A,
LL | | Simple::B => Simple::B,
LL | | Simple::C => Simple::C,
LL | | Simple::D => Simple::D,
LL | | };
| |_____^ help: replace it with: `se`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:65:26
--> $DIR/needless_match.rs:54:26
|
LL | let _: Option<i32> = match x {
| __________________________^
@ -68,7 +46,7 @@ LL | | };
| |_____^ help: replace it with: `x`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:81:31
--> $DIR/needless_match.rs:70:31
|
LL | let _: Result<i32, i32> = match Ok(1) {
| _______________________________^
@ -78,7 +56,7 @@ LL | | };
| |_____^ help: replace it with: `Ok(1)`
error: this match expression is unnecessary
--> $DIR/needless_match.rs:85:31
--> $DIR/needless_match.rs:74:31
|
LL | let _: Result<i32, i32> = match func_ret_err(0_i32) {
| _______________________________^
@ -88,35 +66,48 @@ LL | | };
| |_____^ help: replace it with: `func_ret_err(0_i32)`
error: this if-let expression is unnecessary
--> $DIR/needless_match.rs:92:5
--> $DIR/needless_match.rs:87:5
|
LL | if let Some(a) = Some(1) { Some(a) } else { None }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(1)`
error: this if-let expression is unnecessary
--> $DIR/needless_match.rs:96:30
--> $DIR/needless_match.rs:92:31
|
LL | let _: Result<(), i32> = if let Err(e) = x { Err(e) } else { x };
LL | let _: Result<i32, i32> = if let Err(e) = x { Err(e) } else { x };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x`
error: this if-let expression is unnecessary
--> $DIR/needless_match.rs:97:30
--> $DIR/needless_match.rs:93:31
|
LL | let _: Result<(), i32> = if let Ok(val) = x { Ok(val) } else { x };
LL | let _: Result<i32, i32> = if let Ok(val) = x { Ok(val) } else { x };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x`
error: this if-let expression is unnecessary
--> $DIR/needless_match.rs:103:21
--> $DIR/needless_match.rs:99:21
|
LL | let _: Choice = if let Choice::A = x {
LL | let _: Simple = if let Simple::A = x {
| _____________________^
LL | | Choice::A
LL | | } else if let Choice::B = x {
LL | | Choice::B
LL | | Simple::A
LL | | } else if let Simple::B = x {
LL | | Simple::B
... |
LL | | x
LL | | };
| |_____^ help: replace it with: `x`
error: aborting due to 12 previous errors
error: this match expression is unnecessary
--> $DIR/needless_match.rs:138:26
|
LL | let _: Complex = match ce {
| __________________________^
LL | | Complex::A(a) => Complex::A(a),
LL | | Complex::B(a, b) => Complex::B(a, b),
LL | | Complex::C(a, b, c) => Complex::C(a, b, c),
LL | | Complex::D(E::VariantA(ea, eb), b) => Complex::D(E::VariantA(ea, eb), b),
LL | | Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(ea, eb), b),
LL | | };
| |_________^ help: replace it with: `ce`
error: aborting due to 11 previous errors