new lint: match_like_matches_macro
This commit is contained in:
parent
ac856922f8
commit
2e8a1be444
@ -1513,6 +1513,7 @@ Released 2018-09-13
|
||||
[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
|
||||
[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
|
||||
[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
|
||||
[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
|
||||
[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
|
||||
[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
|
||||
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
|
||||
|
@ -13,14 +13,14 @@ use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::{
|
||||
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind,
|
||||
QPath, RangeEnd,
|
||||
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat,
|
||||
PatKind, QPath, RangeEnd,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::Bound;
|
||||
|
||||
@ -409,6 +409,67 @@ declare_clippy_lint! {
|
||||
"a match on a struct that binds all fields but still uses the wildcard pattern"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Lint for redundant pattern matching over `Result` or
|
||||
/// `Option`
|
||||
///
|
||||
/// **Why is this bad?** It's more concise and clear to just use the proper
|
||||
/// utility function
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
/// if let Err(_) = Err::<i32, i32>(42) {}
|
||||
/// if let None = None::<()> {}
|
||||
/// if let Some(_) = Some(42) {}
|
||||
/// match Ok::<i32, i32>(42) {
|
||||
/// Ok(_) => true,
|
||||
/// Err(_) => false,
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// The more idiomatic use would be:
|
||||
///
|
||||
/// ```rust
|
||||
/// if Ok::<i32, i32>(42).is_ok() {}
|
||||
/// if Err::<i32, i32>(42).is_err() {}
|
||||
/// if None::<()>.is_none() {}
|
||||
/// if Some(42).is_some() {}
|
||||
/// Ok::<i32, i32>(42).is_ok();
|
||||
/// ```
|
||||
pub REDUNDANT_PATTERN_MATCHING,
|
||||
style,
|
||||
"use the proper utility function avoiding an `if let`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `match` expressions producing a `bool` that could be written using `matches!`
|
||||
///
|
||||
/// **Why is this bad?** Readability and needless complexity.
|
||||
///
|
||||
/// **Known problems:** This can turn an intentionally exhaustive match into a non-exhaustive one.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let x = Some(5);
|
||||
///
|
||||
/// // Bad
|
||||
/// let a = match x {
|
||||
/// Some(0) => true,
|
||||
/// _ => false,
|
||||
/// };
|
||||
///
|
||||
/// // Good
|
||||
/// let a = matches!(x, Some(5));
|
||||
/// ```
|
||||
pub MATCH_LIKE_MATCHES_MACRO,
|
||||
style,
|
||||
"a match that could be written with the matches! macro"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Matches {
|
||||
infallible_destructuring_match_linted: bool,
|
||||
@ -427,7 +488,9 @@ impl_lint_pass!(Matches => [
|
||||
WILDCARD_IN_OR_PATTERNS,
|
||||
MATCH_SINGLE_BINDING,
|
||||
INFALLIBLE_DESTRUCTURING_MATCH,
|
||||
REST_PAT_IN_FULLY_BOUND_STRUCTS
|
||||
REST_PAT_IN_FULLY_BOUND_STRUCTS,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
MATCH_LIKE_MATCHES_MACRO
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||
@ -435,6 +498,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !redundant_pattern_match::check(cx, expr) {
|
||||
check_match_like_matches(cx, expr);
|
||||
}
|
||||
|
||||
if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
|
||||
check_single_match(cx, ex, arms, expr);
|
||||
check_match_bool(cx, ex, arms, expr);
|
||||
@ -802,13 +870,8 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
|
||||
// Some simple checks for exhaustive patterns.
|
||||
// There is a room for improvements to detect more cases,
|
||||
// but it can be more expensive to do so.
|
||||
let is_pattern_exhaustive = |pat: &&Pat<'_>| {
|
||||
if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
let is_pattern_exhaustive =
|
||||
|pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None));
|
||||
if patterns.iter().all(is_pattern_exhaustive) {
|
||||
missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
|
||||
}
|
||||
@ -989,6 +1052,78 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
|
||||
fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind {
|
||||
match match_source {
|
||||
MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false),
|
||||
MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true),
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lint a `match` or desugared `if let` for replacement by `matches!`
|
||||
fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) {
|
||||
if_chain! {
|
||||
if arms.len() == 2;
|
||||
if cx.tables().expr_ty(expr).is_bool();
|
||||
if let Some(first) = find_bool_lit(&arms[0].body.kind, desugared);
|
||||
if let Some(second) = find_bool_lit(&arms[1].body.kind, desugared);
|
||||
if first != second;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let pat_and_guard = if let Some(Guard::If(g)) = arms[0].guard {
|
||||
format!("{} if {}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability), snippet_with_applicability(cx, g.span, "..", &mut applicability))
|
||||
} else {
|
||||
format!("{}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability))
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MATCH_LIKE_MATCHES_MACRO,
|
||||
expr.span,
|
||||
&format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }),
|
||||
"try this",
|
||||
format!(
|
||||
"{}matches!({}, {})",
|
||||
if first { "" } else { "!" },
|
||||
snippet_with_applicability(cx, ex.span, "..", &mut applicability),
|
||||
pat_and_guard,
|
||||
),
|
||||
applicability,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract a `bool` or `{ bool }`
|
||||
fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
|
||||
match ex {
|
||||
ExprKind::Lit(Spanned {
|
||||
node: LitKind::Bool(b), ..
|
||||
}) => Some(*b),
|
||||
ExprKind::Block(
|
||||
rustc_hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(exp),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) if desugared => {
|
||||
if let ExprKind::Lit(Spanned {
|
||||
node: LitKind::Bool(b), ..
|
||||
}) = exp.kind
|
||||
{
|
||||
Some(b)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
|
||||
if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
|
||||
return;
|
||||
@ -1179,10 +1314,7 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool {
|
||||
|
||||
// Checks if arm has the form `None => None`
|
||||
fn is_none_arm(arm: &Arm<'_>) -> bool {
|
||||
match arm.pat.kind {
|
||||
PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE))
|
||||
}
|
||||
|
||||
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
|
||||
@ -1293,6 +1425,239 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
mod redundant_pattern_match {
|
||||
use super::REDUNDANT_PATTERN_MATCHING;
|
||||
use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_mir::const_eval::is_const_fn;
|
||||
use rustc_span::source_map::Symbol;
|
||||
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
|
||||
match match_source {
|
||||
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
|
||||
MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
|
||||
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn find_sugg_for_if_let<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
op: &Expr<'_>,
|
||||
arms: &[Arm<'_>],
|
||||
keyword: &'static str,
|
||||
) -> bool {
|
||||
fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
|
||||
if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
|
||||
return Some("is_ok()");
|
||||
}
|
||||
if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
|
||||
return Some("is_err()");
|
||||
}
|
||||
if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
|
||||
return Some("is_some()");
|
||||
}
|
||||
if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
|
||||
return Some("is_none()");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let hir_id = expr.hir_id;
|
||||
let good_method = match arms[0].pat.kind {
|
||||
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
|
||||
if let PatKind::Wild = patterns[0].kind {
|
||||
find_suggestion(cx, hir_id, path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
|
||||
_ => None,
|
||||
};
|
||||
let good_method = match good_method {
|
||||
Some(method) => method,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// check that `while_let_on_iterator` lint does not trigger
|
||||
if_chain! {
|
||||
if keyword == "while";
|
||||
if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
|
||||
if method_path.ident.name == sym!(next);
|
||||
if match_trait_method(cx, op, &paths::ITERATOR);
|
||||
then {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
arms[0].pat.span,
|
||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||
|diag| {
|
||||
// while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
let expr_span = expr.span;
|
||||
|
||||
// while let ... = ... { ... }
|
||||
// ^^^
|
||||
let op_span = op.span.source_callsite();
|
||||
|
||||
// while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
let span = expr_span.until(op_span.shrink_to_hi());
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try this",
|
||||
format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
fn find_sugg_for_match<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
op: &Expr<'_>,
|
||||
arms: &[Arm<'_>],
|
||||
) -> bool {
|
||||
if arms.len() == 2 {
|
||||
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
|
||||
|
||||
let hir_id = expr.hir_id;
|
||||
let found_good_method = match node_pair {
|
||||
(
|
||||
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
|
||||
PatKind::TupleStruct(ref path_right, ref patterns_right, _),
|
||||
) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
|
||||
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
|
||||
find_good_method_for_match(
|
||||
arms,
|
||||
path_left,
|
||||
path_right,
|
||||
&paths::RESULT_OK,
|
||||
&paths::RESULT_ERR,
|
||||
"is_ok()",
|
||||
"is_err()",
|
||||
|| can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
|
||||
|| can_suggest(cx, hir_id, sym!(result_type), "is_err"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
(PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
|
||||
| (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
|
||||
if patterns.len() == 1 =>
|
||||
{
|
||||
if let PatKind::Wild = patterns[0].kind {
|
||||
find_good_method_for_match(
|
||||
arms,
|
||||
path_left,
|
||||
path_right,
|
||||
&paths::OPTION_SOME,
|
||||
&paths::OPTION_NONE,
|
||||
"is_some()",
|
||||
"is_none()",
|
||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_some"),
|
||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_none"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(good_method) = found_good_method {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
expr.span,
|
||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||
|diag| {
|
||||
let span = expr.span.to(op.span);
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try this",
|
||||
format!("{}.{}", snippet(cx, op.span, "_"), good_method),
|
||||
Applicability::MaybeIncorrect, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn find_good_method_for_match<'a>(
|
||||
arms: &[Arm<'_>],
|
||||
path_left: &QPath<'_>,
|
||||
path_right: &QPath<'_>,
|
||||
expected_left: &[&str],
|
||||
expected_right: &[&str],
|
||||
should_be_left: &'a str,
|
||||
should_be_right: &'a str,
|
||||
can_suggest_left: impl Fn() -> bool,
|
||||
can_suggest_right: impl Fn() -> bool,
|
||||
) -> Option<&'a str> {
|
||||
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
|
||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
||||
} else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
|
||||
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
match body_node_pair {
|
||||
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||
(LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
|
||||
(LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
|
||||
if !in_constant(cx, hir_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
|
||||
cx.tcx
|
||||
.get_diagnostic_item(diag_item)
|
||||
.and_then(|def_id| {
|
||||
cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
|
||||
cx.tcx
|
||||
.associated_items(*imp)
|
||||
.in_definition_order()
|
||||
.find_map(|item| match item.kind {
|
||||
ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
})
|
||||
.map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_overlapping() {
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
@ -1,260 +0,0 @@
|
||||
use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_mir::const_eval::is_const_fn;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Lint for redundant pattern matching over `Result` or
|
||||
/// `Option`
|
||||
///
|
||||
/// **Why is this bad?** It's more concise and clear to just use the proper
|
||||
/// utility function
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
/// if let Err(_) = Err::<i32, i32>(42) {}
|
||||
/// if let None = None::<()> {}
|
||||
/// if let Some(_) = Some(42) {}
|
||||
/// match Ok::<i32, i32>(42) {
|
||||
/// Ok(_) => true,
|
||||
/// Err(_) => false,
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// The more idiomatic use would be:
|
||||
///
|
||||
/// ```rust
|
||||
/// if Ok::<i32, i32>(42).is_ok() {}
|
||||
/// if Err::<i32, i32>(42).is_err() {}
|
||||
/// if None::<()>.is_none() {}
|
||||
/// if Some(42).is_some() {}
|
||||
/// Ok::<i32, i32>(42).is_ok();
|
||||
/// ```
|
||||
pub REDUNDANT_PATTERN_MATCHING,
|
||||
style,
|
||||
"use the proper utility function avoiding an `if let`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(RedundantPatternMatching => [REDUNDANT_PATTERN_MATCHING]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for RedundantPatternMatching {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
|
||||
match match_source {
|
||||
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
|
||||
MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
|
||||
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_sugg_for_if_let<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
op: &Expr<'_>,
|
||||
arms: &[Arm<'_>],
|
||||
keyword: &'static str,
|
||||
) {
|
||||
fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
|
||||
if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
|
||||
return Some("is_ok()");
|
||||
}
|
||||
if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
|
||||
return Some("is_err()");
|
||||
}
|
||||
if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
|
||||
return Some("is_some()");
|
||||
}
|
||||
if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
|
||||
return Some("is_none()");
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let hir_id = expr.hir_id;
|
||||
let good_method = match arms[0].pat.kind {
|
||||
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
|
||||
if let PatKind::Wild = patterns[0].kind {
|
||||
find_suggestion(cx, hir_id, path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
|
||||
_ => None,
|
||||
};
|
||||
let good_method = match good_method {
|
||||
Some(method) => method,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// check that `while_let_on_iterator` lint does not trigger
|
||||
if_chain! {
|
||||
if keyword == "while";
|
||||
if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
|
||||
if method_path.ident.name == sym!(next);
|
||||
if match_trait_method(cx, op, &paths::ITERATOR);
|
||||
then {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
arms[0].pat.span,
|
||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||
|diag| {
|
||||
// while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
let expr_span = expr.span;
|
||||
|
||||
// while let ... = ... { ... }
|
||||
// ^^^
|
||||
let op_span = op.span.source_callsite();
|
||||
|
||||
// while let ... = ... { ... }
|
||||
// ^^^^^^^^^^^^^^^^^^^
|
||||
let span = expr_span.until(op_span.shrink_to_hi());
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try this",
|
||||
format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||
if arms.len() == 2 {
|
||||
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
|
||||
|
||||
let hir_id = expr.hir_id;
|
||||
let found_good_method = match node_pair {
|
||||
(
|
||||
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
|
||||
PatKind::TupleStruct(ref path_right, ref patterns_right, _),
|
||||
) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
|
||||
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
|
||||
find_good_method_for_match(
|
||||
arms,
|
||||
path_left,
|
||||
path_right,
|
||||
&paths::RESULT_OK,
|
||||
&paths::RESULT_ERR,
|
||||
"is_ok()",
|
||||
"is_err()",
|
||||
|| can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
|
||||
|| can_suggest(cx, hir_id, sym!(result_type), "is_err"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
(PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
|
||||
| (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
|
||||
if patterns.len() == 1 =>
|
||||
{
|
||||
if let PatKind::Wild = patterns[0].kind {
|
||||
find_good_method_for_match(
|
||||
arms,
|
||||
path_left,
|
||||
path_right,
|
||||
&paths::OPTION_SOME,
|
||||
&paths::OPTION_NONE,
|
||||
"is_some()",
|
||||
"is_none()",
|
||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_some"),
|
||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_none"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(good_method) = found_good_method {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_PATTERN_MATCHING,
|
||||
expr.span,
|
||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||
|diag| {
|
||||
let span = expr.span.to(op.span);
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try this",
|
||||
format!("{}.{}", snippet(cx, op.span, "_"), good_method),
|
||||
Applicability::MaybeIncorrect, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn find_good_method_for_match<'a>(
|
||||
arms: &[Arm<'_>],
|
||||
path_left: &QPath<'_>,
|
||||
path_right: &QPath<'_>,
|
||||
expected_left: &[&str],
|
||||
expected_right: &[&str],
|
||||
should_be_left: &'a str,
|
||||
should_be_right: &'a str,
|
||||
can_suggest_left: impl Fn() -> bool,
|
||||
can_suggest_right: impl Fn() -> bool,
|
||||
) -> Option<&'a str> {
|
||||
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
|
||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
||||
} else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
|
||||
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
match body_node_pair {
|
||||
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||
(LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
|
||||
(LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
|
||||
if !in_constant(cx, hir_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
|
||||
cx.tcx
|
||||
.get_diagnostic_item(diag_item)
|
||||
.and_then(|def_id| {
|
||||
cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
|
||||
cx.tcx
|
||||
.associated_items(*imp)
|
||||
.in_definition_order()
|
||||
.find_map(|item| match item.kind {
|
||||
ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
})
|
||||
.map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
|
||||
}
|
@ -1179,6 +1179,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
||||
deprecation: None,
|
||||
module: "matches",
|
||||
},
|
||||
Lint {
|
||||
name: "match_like_matches_macro",
|
||||
group: "style",
|
||||
desc: "a match that could be written with the matches! macro",
|
||||
deprecation: None,
|
||||
module: "matches",
|
||||
},
|
||||
Lint {
|
||||
name: "match_on_vec_items",
|
||||
group: "pedantic",
|
||||
@ -1856,7 +1863,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
||||
group: "style",
|
||||
desc: "use the proper utility function avoiding an `if let`",
|
||||
deprecation: None,
|
||||
module: "redundant_pattern_matching",
|
||||
module: "matches",
|
||||
},
|
||||
Lint {
|
||||
name: "redundant_pub_crate",
|
||||
|
@ -19,6 +19,7 @@ fn main() {
|
||||
|
||||
let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
|
||||
|
||||
#[allow(clippy::match_like_matches_macro)]
|
||||
let _: Option<Flavor> = desserts_of_the_week
|
||||
.iter()
|
||||
.find(|dessert| match *dessert {
|
||||
|
@ -8,7 +8,7 @@ LL | let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s
|
||||
= help: this is more succinctly expressed by calling `.find_map(..)` instead
|
||||
|
||||
error: called `find(p).map(q)` on an `Iterator`
|
||||
--> $DIR/find_map.rs:22:29
|
||||
--> $DIR/find_map.rs:23:29
|
||||
|
|
||||
LL | let _: Option<Flavor> = desserts_of_the_week
|
||||
| _____________________________^
|
||||
|
32
tests/ui/match_expr_like_matches_macro.fixed
Normal file
32
tests/ui/match_expr_like_matches_macro.fixed
Normal file
@ -0,0 +1,32 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::match_like_matches_macro)]
|
||||
|
||||
fn main() {
|
||||
let x = Some(5);
|
||||
|
||||
// Lint
|
||||
let _y = matches!(x, Some(0));
|
||||
|
||||
// Turn into is_none
|
||||
let _z = x.is_none();
|
||||
|
||||
// Lint
|
||||
let _z = !matches!(x, Some(r) if r == 0);
|
||||
|
||||
// Lint
|
||||
let _zz = matches!(x, Some(5));
|
||||
|
||||
// No lint
|
||||
let _a = match x {
|
||||
Some(_) => false,
|
||||
None => false,
|
||||
};
|
||||
|
||||
// No lint
|
||||
let _a = match x {
|
||||
Some(0) => false,
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
}
|
41
tests/ui/match_expr_like_matches_macro.rs
Normal file
41
tests/ui/match_expr_like_matches_macro.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::match_like_matches_macro)]
|
||||
|
||||
fn main() {
|
||||
let x = Some(5);
|
||||
|
||||
// Lint
|
||||
let _y = match x {
|
||||
Some(0) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// Turn into is_none
|
||||
let _z = match x {
|
||||
Some(_) => false,
|
||||
None => true,
|
||||
};
|
||||
|
||||
// Lint
|
||||
let _z = match x {
|
||||
Some(r) if r == 0 => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
// Lint
|
||||
let _zz = if let Some(5) = x { true } else { false };
|
||||
|
||||
// No lint
|
||||
let _a = match x {
|
||||
Some(_) => false,
|
||||
None => false,
|
||||
};
|
||||
|
||||
// No lint
|
||||
let _a = match x {
|
||||
Some(0) => false,
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
}
|
42
tests/ui/match_expr_like_matches_macro.stderr
Normal file
42
tests/ui/match_expr_like_matches_macro.stderr
Normal file
@ -0,0 +1,42 @@
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:9:14
|
||||
|
|
||||
LL | let _y = match x {
|
||||
| ______________^
|
||||
LL | | Some(0) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_____^ help: try this: `matches!(x, Some(0))`
|
||||
|
|
||||
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/match_expr_like_matches_macro.rs:15:14
|
||||
|
|
||||
LL | let _z = match x {
|
||||
| ______________^
|
||||
LL | | Some(_) => false,
|
||||
LL | | None => true,
|
||||
LL | | };
|
||||
| |_____^ help: try this: `x.is_none()`
|
||||
|
|
||||
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
|
||||
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:21:14
|
||||
|
|
||||
LL | let _z = match x {
|
||||
| ______________^
|
||||
LL | | Some(r) if r == 0 => false,
|
||||
LL | | _ => true,
|
||||
LL | | };
|
||||
| |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
|
||||
|
||||
error: if let .. else expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:27:15
|
||||
|
|
||||
LL | let _zz = if let Some(5) = x { true } else { false };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[allow(clippy::unnested_or_patterns)]
|
||||
#[allow(clippy::unnested_or_patterns, clippy::match_like_matches_macro)]
|
||||
#[warn(clippy::neg_cmp_op_on_partial_ord)]
|
||||
fn main() {
|
||||
let a_value = 1.0;
|
||||
|
@ -23,10 +23,7 @@ pub enum SeemsOption<T> {
|
||||
|
||||
impl<T> SeemsOption<T> {
|
||||
pub fn is_none(&self) -> bool {
|
||||
match *self {
|
||||
SeemsOption::None => true,
|
||||
SeemsOption::Some(_) => false,
|
||||
}
|
||||
matches!(*self, SeemsOption::None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,7 @@ pub enum SeemsOption<T> {
|
||||
|
||||
impl<T> SeemsOption<T> {
|
||||
pub fn is_none(&self) -> bool {
|
||||
match *self {
|
||||
SeemsOption::None => true,
|
||||
SeemsOption::Some(_) => false,
|
||||
}
|
||||
matches!(*self, SeemsOption::None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ LL | | }
|
||||
= note: `-D clippy::question-mark` implied by `-D warnings`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:50:9
|
||||
--> $DIR/question_mark.rs:47:9
|
||||
|
|
||||
LL | / if (self.opt).is_none() {
|
||||
LL | | return None;
|
||||
@ -17,7 +17,7 @@ LL | | }
|
||||
| |_________^ help: replace it with: `(self.opt)?;`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:54:9
|
||||
--> $DIR/question_mark.rs:51:9
|
||||
|
|
||||
LL | / if self.opt.is_none() {
|
||||
LL | | return None
|
||||
@ -25,7 +25,7 @@ LL | | }
|
||||
| |_________^ help: replace it with: `self.opt?;`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:58:17
|
||||
--> $DIR/question_mark.rs:55:17
|
||||
|
|
||||
LL | let _ = if self.opt.is_none() {
|
||||
| _________________^
|
||||
@ -36,7 +36,7 @@ LL | | };
|
||||
| |_________^ help: replace it with: `Some(self.opt?)`
|
||||
|
||||
error: this if-let-else may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:64:17
|
||||
--> $DIR/question_mark.rs:61:17
|
||||
|
|
||||
LL | let _ = if let Some(x) = self.opt {
|
||||
| _________________^
|
||||
@ -47,7 +47,7 @@ LL | | };
|
||||
| |_________^ help: replace it with: `self.opt?`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:81:9
|
||||
--> $DIR/question_mark.rs:78:9
|
||||
|
|
||||
LL | / if self.opt.is_none() {
|
||||
LL | | return None;
|
||||
@ -55,7 +55,7 @@ LL | | }
|
||||
| |_________^ help: replace it with: `self.opt.as_ref()?;`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:89:9
|
||||
--> $DIR/question_mark.rs:86:9
|
||||
|
|
||||
LL | / if self.opt.is_none() {
|
||||
LL | | return None;
|
||||
@ -63,7 +63,7 @@ LL | | }
|
||||
| |_________^ help: replace it with: `self.opt.as_ref()?;`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:97:9
|
||||
--> $DIR/question_mark.rs:94:9
|
||||
|
|
||||
LL | / if self.opt.is_none() {
|
||||
LL | | return None;
|
||||
@ -71,7 +71,7 @@ LL | | }
|
||||
| |_________^ help: replace it with: `self.opt.as_ref()?;`
|
||||
|
||||
error: this if-let-else may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:104:26
|
||||
--> $DIR/question_mark.rs:101:26
|
||||
|
|
||||
LL | let v: &Vec<_> = if let Some(ref v) = self.opt {
|
||||
| __________________________^
|
||||
@ -82,7 +82,7 @@ LL | | };
|
||||
| |_________^ help: replace it with: `self.opt.as_ref()?`
|
||||
|
||||
error: this if-let-else may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:114:17
|
||||
--> $DIR/question_mark.rs:111:17
|
||||
|
|
||||
LL | let v = if let Some(v) = self.opt {
|
||||
| _________________^
|
||||
@ -93,7 +93,7 @@ LL | | };
|
||||
| |_________^ help: replace it with: `self.opt?`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> $DIR/question_mark.rs:129:5
|
||||
--> $DIR/question_mark.rs:126:5
|
||||
|
|
||||
LL | / if f().is_none() {
|
||||
LL | | return None;
|
||||
|
@ -2,7 +2,13 @@
|
||||
|
||||
#![warn(clippy::all)]
|
||||
#![warn(clippy::redundant_pattern_matching)]
|
||||
#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
|
||||
#![allow(
|
||||
clippy::unit_arg,
|
||||
unused_must_use,
|
||||
clippy::needless_bool,
|
||||
clippy::match_like_matches_macro,
|
||||
deprecated
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
if Ok::<i32, i32>(42).is_ok() {}
|
||||
|
@ -2,7 +2,13 @@
|
||||
|
||||
#![warn(clippy::all)]
|
||||
#![warn(clippy::redundant_pattern_matching)]
|
||||
#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
|
||||
#![allow(
|
||||
clippy::unit_arg,
|
||||
unused_must_use,
|
||||
clippy::needless_bool,
|
||||
clippy::match_like_matches_macro,
|
||||
deprecated
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:8:12
|
||||
--> $DIR/redundant_pattern_matching.rs:14:12
|
||||
|
|
||||
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
|
||||
@ -7,67 +7,67 @@ LL | if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:10:12
|
||||
--> $DIR/redundant_pattern_matching.rs:16:12
|
||||
|
|
||||
LL | if let Err(_) = Err::<i32, i32>(42) {}
|
||||
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:12:12
|
||||
--> $DIR/redundant_pattern_matching.rs:18:12
|
||||
|
|
||||
LL | if let None = None::<()> {}
|
||||
| -------^^^^------------- help: try this: `if None::<()>.is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:14:12
|
||||
--> $DIR/redundant_pattern_matching.rs:20:12
|
||||
|
|
||||
LL | if let Some(_) = Some(42) {}
|
||||
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:16:12
|
||||
--> $DIR/redundant_pattern_matching.rs:22:12
|
||||
|
|
||||
LL | if let Some(_) = Some(42) {
|
||||
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:22:15
|
||||
--> $DIR/redundant_pattern_matching.rs:28:15
|
||||
|
|
||||
LL | while let Some(_) = Some(42) {}
|
||||
| ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:24:15
|
||||
--> $DIR/redundant_pattern_matching.rs:30:15
|
||||
|
|
||||
LL | while let None = Some(42) {}
|
||||
| ----------^^^^----------- help: try this: `while Some(42).is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:26:15
|
||||
--> $DIR/redundant_pattern_matching.rs:32:15
|
||||
|
|
||||
LL | while let None = None::<()> {}
|
||||
| ----------^^^^------------- help: try this: `while None::<()>.is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:28:15
|
||||
--> $DIR/redundant_pattern_matching.rs:34:15
|
||||
|
|
||||
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
|
||||
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:30:15
|
||||
--> $DIR/redundant_pattern_matching.rs:36:15
|
||||
|
|
||||
LL | while let Err(_) = Ok::<i32, i32>(10) {}
|
||||
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:33:15
|
||||
--> $DIR/redundant_pattern_matching.rs:39:15
|
||||
|
|
||||
LL | while let Some(_) = v.pop() {
|
||||
| ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:49:5
|
||||
--> $DIR/redundant_pattern_matching.rs:55:5
|
||||
|
|
||||
LL | / match Ok::<i32, i32>(42) {
|
||||
LL | | Ok(_) => true,
|
||||
@ -76,7 +76,7 @@ LL | | };
|
||||
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:54:5
|
||||
--> $DIR/redundant_pattern_matching.rs:60:5
|
||||
|
|
||||
LL | / match Ok::<i32, i32>(42) {
|
||||
LL | | Ok(_) => false,
|
||||
@ -85,7 +85,7 @@ LL | | };
|
||||
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:59:5
|
||||
--> $DIR/redundant_pattern_matching.rs:65:5
|
||||
|
|
||||
LL | / match Err::<i32, i32>(42) {
|
||||
LL | | Ok(_) => false,
|
||||
@ -94,7 +94,7 @@ LL | | };
|
||||
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:64:5
|
||||
--> $DIR/redundant_pattern_matching.rs:70:5
|
||||
|
|
||||
LL | / match Err::<i32, i32>(42) {
|
||||
LL | | Ok(_) => true,
|
||||
@ -103,7 +103,7 @@ LL | | };
|
||||
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:69:5
|
||||
--> $DIR/redundant_pattern_matching.rs:75:5
|
||||
|
|
||||
LL | / match Some(42) {
|
||||
LL | | Some(_) => true,
|
||||
@ -112,7 +112,7 @@ LL | | };
|
||||
| |_____^ help: try this: `Some(42).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:74:5
|
||||
--> $DIR/redundant_pattern_matching.rs:80:5
|
||||
|
|
||||
LL | / match None::<()> {
|
||||
LL | | Some(_) => false,
|
||||
@ -121,7 +121,7 @@ LL | | };
|
||||
| |_____^ help: try this: `None::<()>.is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:79:13
|
||||
--> $DIR/redundant_pattern_matching.rs:85:13
|
||||
|
|
||||
LL | let _ = match None::<()> {
|
||||
| _____________^
|
||||
@ -131,61 +131,61 @@ LL | | };
|
||||
| |_____^ help: try this: `None::<()>.is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:84:20
|
||||
--> $DIR/redundant_pattern_matching.rs:90:20
|
||||
|
|
||||
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
|
||||
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:87:20
|
||||
--> $DIR/redundant_pattern_matching.rs:93:20
|
||||
|
|
||||
LL | let x = if let Some(_) = opt { true } else { false };
|
||||
| -------^^^^^^^------ help: try this: `if opt.is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:93:20
|
||||
--> $DIR/redundant_pattern_matching.rs:99:20
|
||||
|
|
||||
LL | let _ = if let Some(_) = gen_opt() {
|
||||
| -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_none()`
|
||||
--> $DIR/redundant_pattern_matching.rs:95:19
|
||||
--> $DIR/redundant_pattern_matching.rs:101:19
|
||||
|
|
||||
LL | } else if let None = gen_opt() {
|
||||
| -------^^^^------------ help: try this: `if gen_opt().is_none()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_ok()`
|
||||
--> $DIR/redundant_pattern_matching.rs:97:19
|
||||
--> $DIR/redundant_pattern_matching.rs:103:19
|
||||
|
|
||||
LL | } else if let Ok(_) = gen_res() {
|
||||
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_err()`
|
||||
--> $DIR/redundant_pattern_matching.rs:99:19
|
||||
--> $DIR/redundant_pattern_matching.rs:105:19
|
||||
|
|
||||
LL | } else if let Err(_) = gen_res() {
|
||||
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:132:19
|
||||
--> $DIR/redundant_pattern_matching.rs:138:19
|
||||
|
|
||||
LL | while let Some(_) = r#try!(result_opt()) {}
|
||||
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:133:16
|
||||
--> $DIR/redundant_pattern_matching.rs:139:16
|
||||
|
|
||||
LL | if let Some(_) = r#try!(result_opt()) {}
|
||||
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:139:12
|
||||
--> $DIR/redundant_pattern_matching.rs:145:12
|
||||
|
|
||||
LL | if let Some(_) = m!() {}
|
||||
| -------^^^^^^^------- help: try this: `if m!().is_some()`
|
||||
|
||||
error: redundant pattern matching, consider using `is_some()`
|
||||
--> $DIR/redundant_pattern_matching.rs:140:15
|
||||
--> $DIR/redundant_pattern_matching.rs:146:15
|
||||
|
|
||||
LL | while let Some(_) = m!() {}
|
||||
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#![feature(const_result)]
|
||||
#![warn(clippy::redundant_pattern_matching)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::match_like_matches_macro, unused)]
|
||||
|
||||
// Test that results are linted with the feature enabled.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#![feature(const_result)]
|
||||
#![warn(clippy::redundant_pattern_matching)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::match_like_matches_macro, unused)]
|
||||
|
||||
// Test that results are linted with the feature enabled.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user