From bc22407b79e551d0604097155b512b11aa5516b1 Mon Sep 17 00:00:00 2001
From: y21 <30553356+y21@users.noreply.github.com>
Date: Sat, 16 Dec 2023 17:40:32 +0100
Subject: [PATCH] add tests, lint on `while let true` and `matches!(.., true)`

---
 .../src/loops/while_let_on_iterator.rs        |  2 +-
 clippy_lints/src/matches/mod.rs               | 21 ++++--
 .../src/matches/redundant_pattern_match.rs    | 70 +++++++++++++++----
 clippy_lints/src/utils/author.rs              |  1 +
 clippy_utils/src/higher.rs                    |  7 +-
 tests/ui/author/loop.rs                       |  6 +-
 .../branches_sharing_code/shared_at_bottom.rs |  8 ++-
 .../shared_at_bottom.stderr                   | 18 ++---
 tests/ui/collapsible_if.fixed                 |  3 +-
 tests/ui/collapsible_if.rs                    |  3 +-
 tests/ui/collapsible_if.stderr                | 18 ++---
 tests/ui/if_then_some_else_none.rs            |  1 +
 tests/ui/if_then_some_else_none.stderr        | 10 +--
 tests/ui/needless_if.fixed                    |  1 +
 tests/ui/needless_if.rs                       |  1 +
 tests/ui/needless_if.stderr                   | 14 ++--
 tests/ui/nonminimal_bool.rs                   |  7 +-
 tests/ui/nonminimal_bool.stderr               | 26 +++----
 ...dundant_pattern_matching_if_let_true.fixed | 38 ++++++++++
 .../redundant_pattern_matching_if_let_true.rs | 38 ++++++++++
 ...undant_pattern_matching_if_let_true.stderr | 47 +++++++++++++
 21 files changed, 272 insertions(+), 68 deletions(-)
 create mode 100644 tests/ui/redundant_pattern_matching_if_let_true.fixed
 create mode 100644 tests/ui/redundant_pattern_matching_if_let_true.rs
 create mode 100644 tests/ui/redundant_pattern_matching_if_let_true.stderr

diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs
index 21b9efba54c..d070ee74985 100644
--- a/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr)
+    if let Some(higher::WhileLet { if_then, let_pat, let_expr, .. }) = higher::WhileLet::hir(expr)
         // check for `Some(..)` pattern
         && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
         && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index af6894545b8..50494f4819f 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -469,15 +469,15 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Lint for redundant pattern matching over `Result`, `Option`,
-    /// `std::task::Poll` or `std::net::IpAddr`
+    /// `std::task::Poll`, `std::net::IpAddr` or `bool`s
     ///
     /// ### Why is this bad?
     /// It's more concise and clear to just use the proper
-    /// utility function
+    /// utility function or using the condition directly
     ///
     /// ### Known problems
-    /// This will change the drop order for the matched type. Both `if let` and
-    /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
+    /// For suggestions involving bindings in patterns, this will change the drop order for the matched type.
+    /// Both `if let` and `while let` will drop the value at the end of the block, both `if` and `while` will drop the
     /// value before entering the block. For most types this change will not matter, but for a few
     /// types this will not be an acceptable change (e.g. locks). See the
     /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
@@ -499,6 +499,10 @@ declare_clippy_lint! {
     ///     Ok(_) => true,
     ///     Err(_) => false,
     /// };
+    ///
+    /// let cond = true;
+    /// if let true = cond {}
+    /// matches!(cond, true);
     /// ```
     ///
     /// The more idiomatic use would be:
@@ -515,6 +519,10 @@ declare_clippy_lint! {
     /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
     /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
     /// Ok::<i32, i32>(42).is_ok();
+    ///
+    /// let cond = true;
+    /// if cond {}
+    /// cond;
     /// ```
     #[clippy::version = "1.31.0"]
     pub REDUNDANT_PATTERN_MATCHING,
@@ -1019,8 +1027,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if is_direct_expn_of(expr.span, "matches").is_some() {
+            if is_direct_expn_of(expr.span, "matches").is_some()
+                && let [arm, _] = arms
+            {
                 redundant_pattern_match::check_match(cx, expr, ex, arms);
+                redundant_pattern_match::check_matches_true(cx, expr, arm, ex);
             }
 
             if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 81c084b979a..e32261ec1e4 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,7 +1,7 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, walk_span_to_context};
-use clippy_utils::sugg::Sugg;
+use clippy_utils::sugg::{make_unop, Sugg};
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
 use clippy_utils::{higher, is_expn_of, is_trait_method};
@@ -17,8 +17,15 @@ use std::fmt::Write;
 use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
+    if let Some(higher::WhileLet {
+        let_pat,
+        let_expr,
+        let_span,
+        ..
+    }) = higher::WhileLet::hir(expr)
+    {
         find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
+        find_if_let_true(cx, let_pat, let_expr, let_span);
     }
 }
 
@@ -34,26 +41,65 @@ pub(super) fn check_if_let<'tcx>(
     find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
 }
 
+/// Looks for:
+/// * `matches!(expr, true)`
+pub fn check_matches_true<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    arm: &'tcx Arm<'_>,
+    scrutinee: &'tcx Expr<'_>,
+) {
+    find_match_true(
+        cx,
+        arm.pat,
+        scrutinee,
+        expr.span.source_callsite(),
+        "using `matches!` to pattern match a bool",
+    );
+}
+
+/// Looks for any of:
+/// * `if let true = ...`
+/// * `if let false = ...`
+/// * `while let true = ...`
 fn find_if_let_true<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, let_span: Span) {
+    find_match_true(cx, pat, scrutinee, let_span, "using `if let` to pattern match a bool");
+}
+
+/// Common logic between `find_if_let_true` and `check_matches_true`
+fn find_match_true<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &'tcx Pat<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    span: Span,
+    message: &str,
+) {
     if let PatKind::Lit(lit) = pat.kind
         && let ExprKind::Lit(lit) = lit.kind
-        && let LitKind::Bool(is_true) = lit.node
+        && let LitKind::Bool(pat_is_true) = lit.node
     {
-        let mut snip = snippet(cx, scrutinee.span, "..").into_owned();
+        let mut applicability = Applicability::MachineApplicable;
 
-        if !is_true {
-            // Invert condition for `if let false = ...`
-            snip.insert(0, '!');
+        let mut sugg = Sugg::hir_with_context(
+            cx,
+            scrutinee,
+            scrutinee.span.source_callsite().ctxt(),
+            "..",
+            &mut applicability,
+        );
+
+        if !pat_is_true {
+            sugg = make_unop("!", sugg);
         }
 
         span_lint_and_sugg(
             cx,
             REDUNDANT_PATTERN_MATCHING,
-            let_span,
-            "using `if let` to pattern match a boolean",
-            "consider using a regular `if` expression",
-            snip,
-            Applicability::MachineApplicable,
+            span,
+            message,
+            "consider using the condition directly",
+            sugg.to_string(),
+            applicability,
         );
     }
 }
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index e83c04eda20..a8bf142f5d5 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -350,6 +350,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             let_pat,
             let_expr,
             if_then,
+            ..
         }) = higher::WhileLet::hir(expr.value)
         {
             bind!(self, let_pat, let_expr, if_then);
diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs
index b2054bf7d41..ba682813dad 100644
--- a/clippy_utils/src/higher.rs
+++ b/clippy_utils/src/higher.rs
@@ -362,6 +362,9 @@ pub struct WhileLet<'hir> {
     pub let_expr: &'hir Expr<'hir>,
     /// `while let` loop body
     pub if_then: &'hir Expr<'hir>,
+    /// `while let PAT = EXPR`
+    ///        ^^^^^^^^^^^^^^
+    pub let_span: Span,
 }
 
 impl<'hir> WhileLet<'hir> {
@@ -376,9 +379,10 @@ impl<'hir> WhileLet<'hir> {
                             ExprKind::If(
                                 Expr {
                                     kind:
-                                        ExprKind::Let(hir::Let {
+                                        ExprKind::Let(&hir::Let {
                                             pat: let_pat,
                                             init: let_expr,
+                                            span: let_span,
                                             ..
                                         }),
                                     ..
@@ -399,6 +403,7 @@ impl<'hir> WhileLet<'hir> {
                 let_pat,
                 let_expr,
                 if_then,
+                let_span,
             });
         }
         None
diff --git a/tests/ui/author/loop.rs b/tests/ui/author/loop.rs
index d6de21631e2..ff5b6100117 100644
--- a/tests/ui/author/loop.rs
+++ b/tests/ui/author/loop.rs
@@ -1,5 +1,9 @@
 #![feature(stmt_expr_attributes)]
-#![allow(clippy::never_loop, clippy::while_immutable_condition)]
+#![allow(
+    clippy::never_loop,
+    clippy::while_immutable_condition,
+    clippy::redundant_pattern_matching
+)]
 
 fn main() {
     #[clippy::author]
diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.rs b/tests/ui/branches_sharing_code/shared_at_bottom.rs
index d102efa7a58..549908b8770 100644
--- a/tests/ui/branches_sharing_code/shared_at_bottom.rs
+++ b/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -1,6 +1,10 @@
 #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
-#![allow(dead_code)]
-#![allow(clippy::equatable_if_let, clippy::uninlined_format_args)]
+#![allow(
+    clippy::equatable_if_let,
+    clippy::uninlined_format_args,
+    clippy::redundant_pattern_matching,
+    dead_code
+)]
 //@no-rustfix
 // This tests the branches_sharing_code lint at the end of blocks
 
diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_bottom.stderr
index d00717befc1..8223df0fe7b 100644
--- a/tests/ui/branches_sharing_code/shared_at_bottom.stderr
+++ b/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -1,5 +1,5 @@
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:31:5
+  --> $DIR/shared_at_bottom.rs:35:5
    |
 LL | /         let result = false;
 LL | |
@@ -26,7 +26,7 @@ LL ~     result;
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:51:5
+  --> $DIR/shared_at_bottom.rs:55:5
    |
 LL | /         println!("Same end of block");
 LL | |
@@ -40,7 +40,7 @@ LL +     println!("Same end of block");
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:69:5
+  --> $DIR/shared_at_bottom.rs:73:5
    |
 LL | /         println!(
 LL | |
@@ -61,7 +61,7 @@ LL +     );
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:82:9
+  --> $DIR/shared_at_bottom.rs:86:9
    |
 LL | /             println!("Hello World");
 LL | |
@@ -75,7 +75,7 @@ LL +         println!("Hello World");
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:99:5
+  --> $DIR/shared_at_bottom.rs:103:5
    |
 LL | /         let later_used_value = "A string value";
 LL | |
@@ -94,7 +94,7 @@ LL +     println!("{}", later_used_value);
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:113:5
+  --> $DIR/shared_at_bottom.rs:117:5
    |
 LL | /         let simple_examples = "I now identify as a &str :)";
 LL | |
@@ -112,7 +112,7 @@ LL +     println!("This is the new simple_example: {}", simple_examples);
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:179:5
+  --> $DIR/shared_at_bottom.rs:183:5
    |
 LL | /         x << 2
 LL | |
@@ -128,7 +128,7 @@ LL ~     x << 2;
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:188:5
+  --> $DIR/shared_at_bottom.rs:192:5
    |
 LL | /         x * 4
 LL | |
@@ -144,7 +144,7 @@ LL +     x * 4
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:202:44
+  --> $DIR/shared_at_bottom.rs:206:44
    |
 LL |     if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
    |                                            ^^^^^^^^^^^
diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed
index fff6bfcc753..44b0b6e7391 100644
--- a/tests/ui/collapsible_if.fixed
+++ b/tests/ui/collapsible_if.fixed
@@ -3,7 +3,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::nonminimal_bool,
-    clippy::eq_op
+    clippy::eq_op,
+    clippy::redundant_pattern_matching
 )]
 
 #[rustfmt::skip]
diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs
index 70bfea231ae..563a273dcdd 100644
--- a/tests/ui/collapsible_if.rs
+++ b/tests/ui/collapsible_if.rs
@@ -3,7 +3,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::nonminimal_bool,
-    clippy::eq_op
+    clippy::eq_op,
+    clippy::redundant_pattern_matching
 )]
 
 #[rustfmt::skip]
diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr
index e8a36bf48f1..16df3e433db 100644
--- a/tests/ui/collapsible_if.stderr
+++ b/tests/ui/collapsible_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:14:5
+  --> $DIR/collapsible_if.rs:15:5
    |
 LL | /     if x == "hello" {
 LL | |         if y == "world" {
@@ -18,7 +18,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:20:5
+  --> $DIR/collapsible_if.rs:21:5
    |
 LL | /     if x == "hello" || x == "world" {
 LL | |         if y == "world" || y == "hello" {
@@ -35,7 +35,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:26:5
+  --> $DIR/collapsible_if.rs:27:5
    |
 LL | /     if x == "hello" && x == "world" {
 LL | |         if y == "world" || y == "hello" {
@@ -52,7 +52,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:32:5
+  --> $DIR/collapsible_if.rs:33:5
    |
 LL | /     if x == "hello" || x == "world" {
 LL | |         if y == "world" && y == "hello" {
@@ -69,7 +69,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:38:5
+  --> $DIR/collapsible_if.rs:39:5
    |
 LL | /     if x == "hello" && x == "world" {
 LL | |         if y == "world" && y == "hello" {
@@ -86,7 +86,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:44:5
+  --> $DIR/collapsible_if.rs:45:5
    |
 LL | /     if 42 == 1337 {
 LL | |         if 'a' != 'A' {
@@ -103,7 +103,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:100:5
+  --> $DIR/collapsible_if.rs:101:5
    |
 LL | /     if x == "hello" {
 LL | |         if y == "world" { // Collapsible
@@ -120,7 +120,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:159:5
+  --> $DIR/collapsible_if.rs:160:5
    |
 LL | /     if matches!(true, true) {
 LL | |         if matches!(true, true) {}
@@ -128,7 +128,7 @@ LL | |     }
    | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:164:5
+  --> $DIR/collapsible_if.rs:165:5
    |
 LL | /     if matches!(true, true) && truth() {
 LL | |         if matches!(true, true) {}
diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs
index 77abd663e0a..abc92459148 100644
--- a/tests/ui/if_then_some_else_none.rs
+++ b/tests/ui/if_then_some_else_none.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::if_then_some_else_none)]
+#![allow(clippy::redundant_pattern_matching)]
 
 fn main() {
     // Should issue an error.
diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr
index 5c97b06da15..9b3d65cc803 100644
--- a/tests/ui/if_then_some_else_none.stderr
+++ b/tests/ui/if_then_some_else_none.stderr
@@ -1,5 +1,5 @@
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:5:13
+  --> $DIR/if_then_some_else_none.rs:6:13
    |
 LL |       let _ = if foo() {
    |  _____________^
@@ -16,7 +16,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
 
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:14:13
+  --> $DIR/if_then_some_else_none.rs:15:13
    |
 LL |       let _ = if matches!(true, true) {
    |  _____________^
@@ -31,7 +31,7 @@ LL | |     };
    = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
 
 error: this could be simplified with `bool::then_some`
-  --> $DIR/if_then_some_else_none.rs:24:28
+  --> $DIR/if_then_some_else_none.rs:25:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
 
 error: this could be simplified with `bool::then_some`
-  --> $DIR/if_then_some_else_none.rs:29:13
+  --> $DIR/if_then_some_else_none.rs:30:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |     let _ = if !x { Some(0) } else { None };
    = help: consider using `bool::then_some` like: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:85:13
+  --> $DIR/if_then_some_else_none.rs:86:13
    |
 LL |       let _ = if foo() {
    |  _____________^
diff --git a/tests/ui/needless_if.fixed b/tests/ui/needless_if.fixed
index 1086ae2c984..79e33a7218b 100644
--- a/tests/ui/needless_if.fixed
+++ b/tests/ui/needless_if.fixed
@@ -10,6 +10,7 @@
     clippy::nonminimal_bool,
     clippy::short_circuit_statement,
     clippy::unnecessary_operation,
+    clippy::redundant_pattern_matching,
     unused
 )]
 #![warn(clippy::needless_if)]
diff --git a/tests/ui/needless_if.rs b/tests/ui/needless_if.rs
index 131cceaf712..2c135fb22bf 100644
--- a/tests/ui/needless_if.rs
+++ b/tests/ui/needless_if.rs
@@ -10,6 +10,7 @@
     clippy::nonminimal_bool,
     clippy::short_circuit_statement,
     clippy::unnecessary_operation,
+    clippy::redundant_pattern_matching,
     unused
 )]
 #![warn(clippy::needless_if)]
diff --git a/tests/ui/needless_if.stderr b/tests/ui/needless_if.stderr
index c3e83c0f1f5..9a911b4dbac 100644
--- a/tests/ui/needless_if.stderr
+++ b/tests/ui/needless_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:26:5
+  --> $DIR/needless_if.rs:27:5
    |
 LL |     if (true) {}
    |     ^^^^^^^^^^^^ help: you can remove it
@@ -8,13 +8,13 @@ LL |     if (true) {}
    = help: to override `-D warnings` add `#[allow(clippy::needless_if)]`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:28:5
+  --> $DIR/needless_if.rs:29:5
    |
 LL |     if maybe_side_effect() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:33:5
+  --> $DIR/needless_if.rs:34:5
    |
 LL | /     if {
 LL | |         return;
@@ -29,7 +29,7 @@ LL +     });
    |
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:49:5
+  --> $DIR/needless_if.rs:50:5
    |
 LL | /     if {
 LL | |         if let true = true
@@ -54,19 +54,19 @@ LL +     } && true);
    |
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:93:5
+  --> $DIR/needless_if.rs:94:5
    |
 LL |     if { maybe_side_effect() } {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:95:5
+  --> $DIR/needless_if.rs:96:5
    |
 LL |     if { maybe_side_effect() } && true {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:99:5
+  --> $DIR/needless_if.rs:100:5
    |
 LL |     if true {}
    |     ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs
index da7876e772e..4d48ef14d31 100644
--- a/tests/ui/nonminimal_bool.rs
+++ b/tests/ui/nonminimal_bool.rs
@@ -1,6 +1,11 @@
 //@no-rustfix: overlapping suggestions
 #![feature(lint_reasons)]
-#![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)]
+#![allow(
+    unused,
+    clippy::diverging_sub_expression,
+    clippy::needless_if,
+    clippy::redundant_pattern_matching
+)]
 #![warn(clippy::nonminimal_bool)]
 #![allow(clippy::useless_vec)]
 
diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr
index deae389dbef..fd1568d94e3 100644
--- a/tests/ui/nonminimal_bool.stderr
+++ b/tests/ui/nonminimal_bool.stderr
@@ -1,5 +1,5 @@
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:13:13
+  --> $DIR/nonminimal_bool.rs:18:13
    |
 LL |     let _ = !true;
    |             ^^^^^ help: try: `false`
@@ -8,43 +8,43 @@ LL |     let _ = !true;
    = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:16:13
+  --> $DIR/nonminimal_bool.rs:21:13
    |
 LL |     let _ = !false;
    |             ^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:18:13
+  --> $DIR/nonminimal_bool.rs:23:13
    |
 LL |     let _ = !!a;
    |             ^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:20:13
+  --> $DIR/nonminimal_bool.rs:25:13
    |
 LL |     let _ = false || a;
    |             ^^^^^^^^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:25:13
+  --> $DIR/nonminimal_bool.rs:30:13
    |
 LL |     let _ = !(!a && b);
    |             ^^^^^^^^^^ help: try: `a || !b`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:27:13
+  --> $DIR/nonminimal_bool.rs:32:13
    |
 LL |     let _ = !(!a || b);
    |             ^^^^^^^^^^ help: try: `a && !b`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:29:13
+  --> $DIR/nonminimal_bool.rs:34:13
    |
 LL |     let _ = !a && !(b && c);
    |             ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:38:13
+  --> $DIR/nonminimal_bool.rs:43:13
    |
 LL |     let _ = a == b && c == 5 && a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL |     let _ = a == b && c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:40:13
+  --> $DIR/nonminimal_bool.rs:45:13
    |
 LL |     let _ = a == b || c == 5 || a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     let _ = a == b || c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:42:13
+  --> $DIR/nonminimal_bool.rs:47:13
    |
 LL |     let _ = a == b && c == 5 && b == a;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ LL |     let _ = a == b && c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:44:13
+  --> $DIR/nonminimal_bool.rs:49:13
    |
 LL |     let _ = a != b || !(a != b || c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     let _ = a != b || c != d;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:46:13
+  --> $DIR/nonminimal_bool.rs:51:13
    |
 LL |     let _ = a != b && !(a != b && c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     let _ = a != b && c != d;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:77:8
+  --> $DIR/nonminimal_bool.rs:82:8
    |
 LL |     if matches!(true, true) && true {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
diff --git a/tests/ui/redundant_pattern_matching_if_let_true.fixed b/tests/ui/redundant_pattern_matching_if_let_true.fixed
new file mode 100644
index 00000000000..6d910678934
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_if_let_true.fixed
@@ -0,0 +1,38 @@
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(clippy::needless_if, clippy::no_effect, clippy::nonminimal_bool)]
+
+macro_rules! condition {
+    () => {
+        true
+    };
+}
+
+macro_rules! lettrue {
+    (if) => {
+        if let true = true {}
+    };
+    (while) => {
+        while let true = true {}
+    };
+}
+
+fn main() {
+    let mut k = 5;
+
+    if k > 1 {}
+    if !(k > 5) {}
+    if k > 1 {}
+    if let (true, true) = (k > 1, k > 2) {}
+    while k > 1 {
+        k += 1;
+    }
+    while condition!() {
+        k += 1;
+    }
+
+    k > 5;
+    !(k > 5);
+    // Whole loop is from a macro expansion, don't lint:
+    lettrue!(if);
+    lettrue!(while);
+}
diff --git a/tests/ui/redundant_pattern_matching_if_let_true.rs b/tests/ui/redundant_pattern_matching_if_let_true.rs
new file mode 100644
index 00000000000..a82e673982a
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_if_let_true.rs
@@ -0,0 +1,38 @@
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(clippy::needless_if, clippy::no_effect, clippy::nonminimal_bool)]
+
+macro_rules! condition {
+    () => {
+        true
+    };
+}
+
+macro_rules! lettrue {
+    (if) => {
+        if let true = true {}
+    };
+    (while) => {
+        while let true = true {}
+    };
+}
+
+fn main() {
+    let mut k = 5;
+
+    if let true = k > 1 {}
+    if let false = k > 5 {}
+    if let (true) = k > 1 {}
+    if let (true, true) = (k > 1, k > 2) {}
+    while let true = k > 1 {
+        k += 1;
+    }
+    while let true = condition!() {
+        k += 1;
+    }
+
+    matches!(k > 5, true);
+    matches!(k > 5, false);
+    // Whole loop is from a macro expansion, don't lint:
+    lettrue!(if);
+    lettrue!(while);
+}
diff --git a/tests/ui/redundant_pattern_matching_if_let_true.stderr b/tests/ui/redundant_pattern_matching_if_let_true.stderr
new file mode 100644
index 00000000000..211a332d79a
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_if_let_true.stderr
@@ -0,0 +1,47 @@
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:22:8
+   |
+LL |     if let true = k > 1 {}
+   |        ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:23:8
+   |
+LL |     if let false = k > 5 {}
+   |        ^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:24:8
+   |
+LL |     if let (true) = k > 1 {}
+   |        ^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:26:11
+   |
+LL |     while let true = k > 1 {
+   |           ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:29:11
+   |
+LL |     while let true = condition!() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `condition!()`
+
+error: using `matches!` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:33:5
+   |
+LL |     matches!(k > 5, true);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 5`
+
+error: using `matches!` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:34:5
+   |
+LL |     matches!(k > 5, false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)`
+
+error: aborting due to 7 previous errors
+