about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJ-ZhengLi <lizheng135@huawei.com>2022-03-16 16:26:56 +0800
committerJ-ZhengLi <lizheng135@huawei.com>2022-03-16 16:26:56 +0800
commit2909b33a243591cec6a5d6d51dc6e1684809aeac (patch)
treeeee296a44abbff6db56e33bc53222e51f0185434
parentb83c6323c7d788fe4b6921b000324fb09945e12b (diff)
downloadrust-2909b33a243591cec6a5d6d51dc6e1684809aeac.tar.gz
rust-2909b33a243591cec6a5d6d51dc6e1684809aeac.zip
quick fix of issue#8542 for lint `[needless_match]`
remove `ref`/`ref mut` check
-rw-r--r--clippy_lints/src/matches/needless_match.rs61
-rw-r--r--tests/ui/needless_match.fixed116
-rw-r--r--tests/ui/needless_match.rs148
-rw-r--r--tests/ui/needless_match.stderr83
4 files changed, 257 insertions, 151 deletions
diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index 76131d307d7..d9544e18b18 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 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
 }
diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed
index ece18ad737f..6a518f83925 100644
--- a/tests/ui/needless_match.fixed
+++ b/tests/ui/needless_match.fixed
@@ -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() {}
diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs
index 36649de35a6..ffc6a291a15 100644
--- a/tests/ui/needless_match.rs
+++ b/tests/ui/needless_match.rs
@@ -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() {}
diff --git a/tests/ui/needless_match.stderr b/tests/ui/needless_match.stderr
index ad1525406ad..67bd84d6bbc 100644
--- a/tests/ui/needless_match.stderr
+++ b/tests/ui/needless_match.stderr
@@ -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 };
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `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 };
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `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