Auto merge of #11974 - y21:if_let_true, r=llogiq

[`redundant_pattern_matching`]: lint `if let true`, `while let true`, `matches!(.., true)`

Closes #11917

This could also lint e.g. `if let (true, true, false) = (a, b, c)` and suggest `if a && b && c`, but that's a change in semantics (going from eager to lazy, so I just left it out for now. Could be a future improvement.

changelog: [`redundant_pattern_matching`]: lint `if let true`, `while let true`, `matches!(.., true)`
This commit is contained in:
bors 2023-12-16 18:08:22 +00:00
commit b918434717
28 changed files with 312 additions and 70 deletions

View File

@ -57,7 +57,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
arms.iter().any(|arm| is_format(cx, arm.body))
},
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => {
is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
},
_ => false,

View File

@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
span: Span,
) {
let inner_expr = peel_blocks_with_stmt(body);
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. })
= higher::IfLet::hir(cx, inner_expr)
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
&& let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind

View File

@ -14,7 +14,7 @@
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)

View File

@ -61,7 +61,7 @@ pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'t
&& let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
{
match if_let_or_match {
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
&& let Some(if_else) = if_else
&& is_never_expr(cx, if_else).is_some()

View File

@ -41,7 +41,7 @@ fn check_arm<'tcx>(
let inner_expr = peel_blocks_with_stmt(outer_then_body);
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
&& let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)),
IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)),
IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
// if there are more than two arms, collapsing would be non-trivial
// one of the arms must be "wild-like"
@ -75,7 +75,7 @@ fn check_arm<'tcx>(
)
// ...or anywhere in the inner expression
&& match inner {
IfLetOrMatch::IfLet(_, _, body, els) => {
IfLetOrMatch::IfLet(_, _, body, els, _) => {
!is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
},
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),

View File

@ -469,15 +469,15 @@
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 @@
/// Ok(_) => true,
/// Err(_) => false,
/// };
///
/// let cond = true;
/// if let true = cond {}
/// matches!(cond, true);
/// ```
///
/// The more idiomatic use would be:
@ -515,6 +519,10 @@
/// 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
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) {
@ -1104,6 +1115,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_let.let_pat,
if_let.let_expr,
if_let.if_else.is_some(),
if_let.let_span,
);
needless_match::check_if_let(cx, expr, &if_let);
}

View File

@ -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};
@ -12,13 +12,20 @@
use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_span::{sym, Symbol};
use rustc_span::{sym, Span, Symbol};
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) {
find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
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);
}
}
@ -28,8 +35,73 @@ pub(super) fn check_if_let<'tcx>(
pat: &'tcx Pat<'_>,
scrutinee: &'tcx Expr<'_>,
has_else: bool,
let_span: Span,
) {
find_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
find_if_let_true(cx, pat, scrutinee, let_span);
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(pat_is_true) = lit.node
{
let mut applicability = Applicability::MachineApplicable;
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,
span,
message,
"consider using the condition directly",
sugg.to_string(),
applicability,
);
}
}
// Extract the generic arguments out of a type
@ -100,7 +172,7 @@ fn find_method_and_type<'tcx>(
}
}
fn find_sugg_for_if_let<'tcx>(
fn find_method_sugg_for_if_let<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
let_pat: &Pat<'_>,

View File

@ -186,7 +186,7 @@ pub fn check_map_call(
match higher::IfLetOrMatch::parse(cx, map_body.value) {
// For `if let` we want to check that the variant matching arm references the local created by
// its pattern
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_), ..))
if let Some((ident, span)) = expr_uses_local(pat, then) =>
{
(sc, else_, ident, span)

View File

@ -238,6 +238,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
let_expr,
if_then,
if_else: Some(if_else),
..
}) = higher::IfLet::hir(cx, expr)
&& !cx.typeck_results().expr_ty(expr).is_unit()
&& !is_else_clause(cx.tcx, expr)

View File

@ -256,6 +256,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>
let_expr,
if_then,
if_else,
..
}) = higher::IfLet::hir(cx, expr)
&& !is_else_clause(cx.tcx, expr)
&& let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind

View File

@ -350,6 +350,7 @@ fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
let_pat,
let_expr,
if_then,
..
}) = higher::WhileLet::hir(expr.value)
{
bind!(self, let_pat, let_expr, if_then);

View File

@ -91,6 +91,9 @@ pub struct IfLet<'hir> {
pub if_then: &'hir Expr<'hir>,
/// `if let` else expression
pub if_else: Option<&'hir Expr<'hir>>,
/// `if let PAT = EXPR`
/// ^^^^^^^^^^^^^^
pub let_span: Span,
}
impl<'hir> IfLet<'hir> {
@ -99,9 +102,10 @@ pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
if let ExprKind::If(
Expr {
kind:
ExprKind::Let(hir::Let {
ExprKind::Let(&hir::Let {
pat: let_pat,
init: let_expr,
span: let_span,
..
}),
..
@ -129,6 +133,7 @@ pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
let_expr,
if_then,
if_else,
let_span,
});
}
None
@ -146,6 +151,9 @@ pub enum IfLetOrMatch<'hir> {
&'hir Pat<'hir>,
&'hir Expr<'hir>,
Option<&'hir Expr<'hir>>,
/// `if let PAT = EXPR`
/// ^^^^^^^^^^^^^^
Span,
),
}
@ -160,7 +168,8 @@ pub fn parse(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
let_pat,
if_then,
if_else,
}| { Self::IfLet(let_expr, let_pat, if_then, if_else) },
let_span,
}| { Self::IfLet(let_expr, let_pat, if_then, if_else, let_span) },
),
}
}
@ -353,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> {
@ -367,9 +379,10 @@ pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
ExprKind::If(
Expr {
kind:
ExprKind::Let(hir::Let {
ExprKind::Let(&hir::Let {
pat: let_pat,
init: let_expr,
span: let_span,
..
}),
..
@ -390,6 +403,7 @@ pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
let_pat,
let_expr,
if_then,
let_span,
});
}
None

View File

@ -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]

View File

@ -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

View File

@ -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; }
| ^^^^^^^^^^^

View File

@ -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]

View File

@ -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]

View File

@ -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) {}

View File

@ -1,4 +1,5 @@
#![warn(clippy::if_then_some_else_none)]
#![allow(clippy::redundant_pattern_matching)]
fn main() {
// Should issue an error.

View File

@ -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() {
| _____________^

View File

@ -10,6 +10,7 @@
clippy::nonminimal_bool,
clippy::short_circuit_statement,
clippy::unnecessary_operation,
clippy::redundant_pattern_matching,
unused
)]
#![warn(clippy::needless_if)]

View File

@ -10,6 +10,7 @@
clippy::nonminimal_bool,
clippy::short_circuit_statement,
clippy::unnecessary_operation,
clippy::redundant_pattern_matching,
unused
)]
#![warn(clippy::needless_if)]

View File

@ -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;`

View File

@ -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)]

View File

@ -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)`

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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