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:
commit
b918434717
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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)),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<'_>,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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; }
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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) {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(clippy::if_then_some_else_none)]
|
||||
#![allow(clippy::redundant_pattern_matching)]
|
||||
|
||||
fn main() {
|
||||
// Should issue an error.
|
||||
|
@ -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() {
|
||||
| _____________^
|
||||
|
@ -10,6 +10,7 @@
|
||||
clippy::nonminimal_bool,
|
||||
clippy::short_circuit_statement,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::redundant_pattern_matching,
|
||||
unused
|
||||
)]
|
||||
#![warn(clippy::needless_if)]
|
||||
|
@ -10,6 +10,7 @@
|
||||
clippy::nonminimal_bool,
|
||||
clippy::short_circuit_statement,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::redundant_pattern_matching,
|
||||
unused
|
||||
)]
|
||||
#![warn(clippy::needless_if)]
|
||||
|
@ -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;`
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -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)`
|
||||
|
38
tests/ui/redundant_pattern_matching_if_let_true.fixed
Normal file
38
tests/ui/redundant_pattern_matching_if_let_true.fixed
Normal 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);
|
||||
}
|
38
tests/ui/redundant_pattern_matching_if_let_true.rs
Normal file
38
tests/ui/redundant_pattern_matching_if_let_true.rs
Normal 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);
|
||||
}
|
47
tests/ui/redundant_pattern_matching_if_let_true.stderr
Normal file
47
tests/ui/redundant_pattern_matching_if_let_true.stderr
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user