about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-08 15:02:35 +0000
committerbors <bors@rust-lang.org>2024-09-08 15:02:35 +0000
commitbcf528bdefa8eb9a267a877414a54e478d684d02 (patch)
treed8254795e8e9c71b68928762c141798d098bcaa1
parent41dc86d4d39df1efba899a612296bb3ce5af7472 (diff)
parente3ca249e9647396b9a3849e147aa53e168cf4c73 (diff)
downloadrust-bcf528bdefa8eb9a267a877414a54e478d684d02.tar.gz
rust-bcf528bdefa8eb9a267a877414a54e478d684d02.zip
Auto merge of #13324 - WeiTheShinobi:single_match, r=dswij
[`single_match`, `single_match_else`] fix suggestion when match irrefutable

fixes #13012

changelog:[`single_match`, `single_match_else`]: fix suggestion when `match` irrefutable
-rw-r--r--clippy_lints/src/matches/single_match.rs27
-rw-r--r--tests/ui/single_match.fixed24
-rw-r--r--tests/ui/single_match.rs42
-rw-r--r--tests/ui/single_match.stderr67
-rw-r--r--tests/ui/single_match_else.fixed4
-rw-r--r--tests/ui/single_match_else.rs10
-rw-r--r--tests/ui/single_match_else.stderr14
7 files changed, 184 insertions, 4 deletions
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index b6930f7b9d1..e7cef5bdbd7 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{expr_block, snippet, SpanRangeExt};
+use clippy_utils::source::{expr_block, snippet, snippet_block_with_context, SpanRangeExt};
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{
     is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
@@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_pat, Visitor};
-use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef};
 use rustc_span::{sym, Span};
@@ -91,6 +91,29 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
         format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app))
     });
 
+    if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") {
+        let msg = "this pattern is irrefutable, `match` is useless";
+        let (sugg, help) = if is_unit_expr(arm.body) {
+            (String::new(), "`match` expression can be removed")
+        } else {
+            let mut sugg = snippet_block_with_context(cx, arm.body.span, ctxt, "..", Some(expr.span), &mut app)
+                .0
+                .to_string();
+            if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id)
+                && let StmtKind::Expr(_) = stmt.kind
+                && match arm.body.kind {
+                    ExprKind::Block(block, _) => block.span.from_expansion(),
+                    _ => true,
+                }
+            {
+                sugg.push(';');
+            }
+            (sugg, "try")
+        };
+        span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg.to_string(), app);
+        return;
+    }
+
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
     let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
         && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed
index 5249c440889..dcf5a1d33c2 100644
--- a/tests/ui/single_match.fixed
+++ b/tests/ui/single_match.fixed
@@ -296,3 +296,27 @@ fn issue11365() {
 
     if let Some(A | B) = &Some(A) { println!() }
 }
+
+#[derive(Eq, PartialEq)]
+pub struct Data([u8; 4]);
+
+const DATA: Data = Data([1, 2, 3, 4]);
+const CONST_I32: i32 = 1;
+
+fn irrefutable_match() {
+    println!();
+
+    println!();
+
+    let i = 0;
+    {
+        let a = 1;
+        let b = 2;
+    }
+
+    
+
+    
+
+    println!()
+}
diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs
index 882098a56e7..3ba5eebd01b 100644
--- a/tests/ui/single_match.rs
+++ b/tests/ui/single_match.rs
@@ -360,3 +360,45 @@ fn issue11365() {
         None | Some(_) => {},
     }
 }
+
+#[derive(Eq, PartialEq)]
+pub struct Data([u8; 4]);
+
+const DATA: Data = Data([1, 2, 3, 4]);
+const CONST_I32: i32 = 1;
+
+fn irrefutable_match() {
+    match DATA {
+        DATA => println!(),
+        _ => {},
+    }
+
+    match CONST_I32 {
+        CONST_I32 => println!(),
+        _ => {},
+    }
+
+    let i = 0;
+    match i {
+        i => {
+            let a = 1;
+            let b = 2;
+        },
+        _ => {},
+    }
+
+    match i {
+        i => {},
+        _ => {},
+    }
+
+    match i {
+        i => (),
+        _ => (),
+    }
+
+    match CONST_I32 {
+        CONST_I32 => println!(),
+        _ => {},
+    }
+}
diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr
index ceb2a193bf7..9240b09c50a 100644
--- a/tests/ui/single_match.stderr
+++ b/tests/ui/single_match.stderr
@@ -216,5 +216,70 @@ LL | |         None | Some(_) => {},
 LL | |     }
    | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }`
 
-error: aborting due to 20 previous errors
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match.rs:371:5
+   |
+LL | /     match DATA {
+LL | |         DATA => println!(),
+LL | |         _ => {},
+LL | |     }
+   | |_____^ help: try: `println!();`
+
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match.rs:376:5
+   |
+LL | /     match CONST_I32 {
+LL | |         CONST_I32 => println!(),
+LL | |         _ => {},
+LL | |     }
+   | |_____^ help: try: `println!();`
+
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match.rs:382:5
+   |
+LL | /     match i {
+LL | |         i => {
+LL | |             let a = 1;
+LL | |             let b = 2;
+LL | |         },
+LL | |         _ => {},
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     {
+LL +         let a = 1;
+LL +         let b = 2;
+LL +     }
+   |
+
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match.rs:390:5
+   |
+LL | /     match i {
+LL | |         i => {},
+LL | |         _ => {},
+LL | |     }
+   | |_____^ help: `match` expression can be removed
+
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match.rs:395:5
+   |
+LL | /     match i {
+LL | |         i => (),
+LL | |         _ => (),
+LL | |     }
+   | |_____^ help: `match` expression can be removed
+
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match.rs:400:5
+   |
+LL | /     match CONST_I32 {
+LL | |         CONST_I32 => println!(),
+LL | |         _ => {},
+LL | |     }
+   | |_____^ help: try: `println!()`
+
+error: aborting due to 26 previous errors
 
diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed
index 163be16ad8b..c2ca746976b 100644
--- a/tests/ui/single_match_else.fixed
+++ b/tests/ui/single_match_else.fixed
@@ -171,3 +171,7 @@ fn issue_10808(bar: Option<i32>) {
         },
     }
 }
+
+fn irrefutable_match() -> Option<&'static ExprNode> {
+    Some(&NODE)
+}
diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs
index 3f1fd2b3183..2d9e877ee0f 100644
--- a/tests/ui/single_match_else.rs
+++ b/tests/ui/single_match_else.rs
@@ -199,3 +199,13 @@ fn issue_10808(bar: Option<i32>) {
         },
     }
 }
+
+fn irrefutable_match() -> Option<&'static ExprNode> {
+    match ExprNode::Butterflies {
+        ExprNode::Butterflies => Some(&NODE),
+        _ => {
+            let x = 5;
+            None
+        },
+    }
+}
diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr
index 61c348260d0..a2801751a43 100644
--- a/tests/ui/single_match_else.stderr
+++ b/tests/ui/single_match_else.stderr
@@ -197,5 +197,17 @@ LL +         println!("None");
 LL +     }
    |
 
-error: aborting due to 9 previous errors
+error: this pattern is irrefutable, `match` is useless
+  --> tests/ui/single_match_else.rs:204:5
+   |
+LL | /     match ExprNode::Butterflies {
+LL | |         ExprNode::Butterflies => Some(&NODE),
+LL | |         _ => {
+LL | |             let x = 5;
+LL | |             None
+LL | |         },
+LL | |     }
+   | |_____^ help: try: `Some(&NODE)`
+
+error: aborting due to 10 previous errors