Auto merge of #4960 - ThibsG:patterns_with_wildcard_#4640, r=flip1995

New lint: pats_with_wild_match_arm

Wildcard use with other pattern in same match arm.

The wildcard covers other(s) pattern(s) as it will match anyway.

changelog: add new lint when multiple patterns (including wildcard) are used in a match arm.

Fixes #4640.
This commit is contained in:
bors 2020-01-09 13:51:00 +00:00
commit ac795a6f3a
10 changed files with 145 additions and 11 deletions

View file

@ -600,6 +600,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
&matches::SINGLE_MATCH,
&matches::SINGLE_MATCH_ELSE,
&matches::WILDCARD_ENUM_MATCH_ARM,
&matches::WILDCARD_IN_OR_PATTERNS,
&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
&mem_forget::MEM_FORGET,
&mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
@ -1188,6 +1189,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
LintId::of(&matches::MATCH_REF_PATS),
LintId::of(&matches::MATCH_WILD_ERR_ARM),
LintId::of(&matches::SINGLE_MATCH),
LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
@ -1462,6 +1464,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(&matches::MATCH_AS_REF),
LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(&methods::CHARS_NEXT_CMP),
LintId::of(&methods::CLONE_ON_COPY),
LintId::of(&methods::FILTER_NEXT),

View file

@ -3,7 +3,8 @@ use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::{
expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty,
snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint,
walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::declare_lint_pass;
@ -223,6 +224,26 @@ declare_clippy_lint! {
"a wildcard enum match arm using `_`"
}
declare_clippy_lint! {
/// **What it does:** Checks for wildcard pattern used with others patterns in same match arm.
///
/// **Why is this bad?** Wildcard pattern already covers any other pattern as it will match anyway.
/// It makes the code less readable, especially to spot wildcard pattern use in match arm.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// match "foo" {
/// "a" => {},
/// "bar" | _ => {},
/// }
/// ```
pub WILDCARD_IN_OR_PATTERNS,
complexity,
"a wildcard pattern used with others patterns in same match arm"
}
declare_lint_pass!(Matches => [
SINGLE_MATCH,
MATCH_REF_PATS,
@ -231,7 +252,8 @@ declare_lint_pass!(Matches => [
MATCH_OVERLAPPING_ARM,
MATCH_WILD_ERR_ARM,
MATCH_AS_REF,
WILDCARD_ENUM_MATCH_ARM
WILDCARD_ENUM_MATCH_ARM,
WILDCARD_IN_OR_PATTERNS
]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
@ -246,6 +268,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
check_wild_err_arm(cx, ex, arms);
check_wild_enum_match(cx, ex, arms);
check_match_as_ref(cx, ex, arms, expr);
check_wild_in_or_pats(cx, arms);
}
if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
check_match_ref_pats(cx, ex, arms, expr);
@ -664,6 +687,23 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>],
}
}
fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
for arm in arms {
if let PatKind::Or(ref fields) = arm.pat.kind {
// look for multiple fields in this arm that contains at least one Wild pattern
if fields.len() > 1 && fields.iter().any(is_wild) {
span_help_and_lint(
cx,
WILDCARD_IN_OR_PATTERNS,
arm.pat.span,
"wildcard pattern covers any other pattern as it will match anyway.",
"Consider handling `_` separately.",
);
}
}
}
}
/// Gets all arms that are unbounded `PatRange`s.
fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm<'_>]) -> Vec<SpannedRange<Constant>> {
arms.iter()