diff options
| author | robojumper <robojumper@gmail.com> | 2020-07-05 22:10:59 +0200 |
|---|---|---|
| committer | robojumper <robojumper@gmail.com> | 2020-07-06 18:25:20 +0200 |
| commit | 2e8a1be444afc6a9b5137d3e7e4fdcfcb1f89e0d (patch) | |
| tree | 9d9a666d2ad727ea925b463103f4a1272948177d | |
| parent | ac856922f80e9ef8cd95c3004699e4bc8fa0c978 (diff) | |
| download | rust-2e8a1be444afc6a9b5137d3e7e4fdcfcb1f89e0d.tar.gz rust-2e8a1be444afc6a9b5137d3e7e4fdcfcb1f89e0d.zip | |
new lint: match_like_matches_macro
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | clippy_lints/src/matches.rs | 395 | ||||
| -rw-r--r-- | clippy_lints/src/redundant_pattern_matching.rs | 260 | ||||
| -rw-r--r-- | src/lintlist/mod.rs | 9 | ||||
| -rw-r--r-- | tests/ui/find_map.rs | 1 | ||||
| -rw-r--r-- | tests/ui/find_map.stderr | 2 | ||||
| -rw-r--r-- | tests/ui/match_expr_like_matches_macro.fixed | 32 | ||||
| -rw-r--r-- | tests/ui/match_expr_like_matches_macro.rs | 41 | ||||
| -rw-r--r-- | tests/ui/match_expr_like_matches_macro.stderr | 42 | ||||
| -rw-r--r-- | tests/ui/neg_cmp_op_on_partial_ord.rs | 2 | ||||
| -rw-r--r-- | tests/ui/question_mark.fixed | 5 | ||||
| -rw-r--r-- | tests/ui/question_mark.rs | 5 | ||||
| -rw-r--r-- | tests/ui/question_mark.stderr | 20 | ||||
| -rw-r--r-- | tests/ui/redundant_pattern_matching.fixed | 8 | ||||
| -rw-r--r-- | tests/ui/redundant_pattern_matching.rs | 8 | ||||
| -rw-r--r-- | tests/ui/redundant_pattern_matching.stderr | 56 | ||||
| -rw-r--r-- | tests/ui/redundant_pattern_matching_const_result.fixed | 2 | ||||
| -rw-r--r-- | tests/ui/redundant_pattern_matching_const_result.rs | 2 |
18 files changed, 563 insertions, 328 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a081bb85fe..6261ca4879a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index b754a45aa40..34aa2981535 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -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; diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs deleted file mode 100644 index d8d16efb978..00000000000 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ /dev/null @@ -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)) -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index e681f47f949..888b4755484 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1180,6 +1180,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ 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", desc: "matching on vector elements can panic", @@ -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", diff --git a/tests/ui/find_map.rs b/tests/ui/find_map.rs index c28cca144ca..88d3b0e7490 100644 --- a/tests/ui/find_map.rs +++ b/tests/ui/find_map.rs @@ -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 { diff --git a/tests/ui/find_map.stderr b/tests/ui/find_map.stderr index 92f40fe6f1f..f279850fef8 100644 --- a/tests/ui/find_map.stderr +++ b/tests/ui/find_map.stderr @@ -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 | _____________________________^ diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed new file mode 100644 index 00000000000..2d1ac8836d6 --- /dev/null +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -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, + }; +} diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs new file mode 100644 index 00000000000..376abf9244e --- /dev/null +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -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, + }; +} diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr new file mode 100644 index 00000000000..0b32af039a8 --- /dev/null +++ b/tests/ui/match_expr_like_matches_macro.stderr @@ -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 + diff --git a/tests/ui/neg_cmp_op_on_partial_ord.rs b/tests/ui/neg_cmp_op_on_partial_ord.rs index ca70e3b7148..0cee0a28fc7 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -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; diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 11dff94a288..bd13cf1bdfa 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -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) } } diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 1d0ee82b4f7..94479e68555 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -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) } } diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 502615fb175..be323035d6c 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -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; diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 8b4e2d21331..ce8582d2b22 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -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() {} diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index b0904e41b6f..a3a9aa40e3b 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -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) {} diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 51a6f4350d3..25d1476062e 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -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()` diff --git a/tests/ui/redundant_pattern_matching_const_result.fixed b/tests/ui/redundant_pattern_matching_const_result.fixed index 8a81e92f04a..de3fe00d5fa 100644 --- a/tests/ui/redundant_pattern_matching_const_result.fixed +++ b/tests/ui/redundant_pattern_matching_const_result.fixed @@ -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. diff --git a/tests/ui/redundant_pattern_matching_const_result.rs b/tests/ui/redundant_pattern_matching_const_result.rs index 1cd515441d1..b77969d53d9 100644 --- a/tests/ui/redundant_pattern_matching_const_result.rs +++ b/tests/ui/redundant_pattern_matching_const_result.rs @@ -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. |
