@@ -3,7 +3,8 @@ use crate::utils::paths;
33use crate :: utils:: sugg:: Sugg ;
44use crate :: utils:: {
55 expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
6- snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty,
6+ snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint,
7+ walk_ptrs_ty,
78} ;
89use if_chain:: if_chain;
910use rustc:: declare_lint_pass;
@@ -223,6 +224,26 @@ declare_clippy_lint! {
223224 "a wildcard enum match arm using `_`"
224225}
225226
227+ declare_clippy_lint ! {
228+ /// **What it does:** Checks for wildcard pattern used with others patterns in same match arm.
229+ ///
230+ /// **Why is this bad?** Wildcard pattern already covers any other pattern as it will match anyway.
231+ /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
232+ ///
233+ /// **Known problems:** None.
234+ ///
235+ /// **Example:**
236+ /// ```rust
237+ /// match "foo" {
238+ /// "a" => {},
239+ /// "bar" | _ => {},
240+ /// }
241+ /// ```
242+ pub WILDCARD_IN_OR_PATTERNS ,
243+ complexity,
244+ "a wildcard pattern used with others patterns in same match arm"
245+ }
246+
226247declare_lint_pass ! ( Matches => [
227248 SINGLE_MATCH ,
228249 MATCH_REF_PATS ,
@@ -231,7 +252,8 @@ declare_lint_pass!(Matches => [
231252 MATCH_OVERLAPPING_ARM ,
232253 MATCH_WILD_ERR_ARM ,
233254 MATCH_AS_REF ,
234- WILDCARD_ENUM_MATCH_ARM
255+ WILDCARD_ENUM_MATCH_ARM ,
256+ WILDCARD_IN_OR_PATTERNS
235257] ) ;
236258
237259impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Matches {
@@ -246,6 +268,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
246268 check_wild_err_arm ( cx, ex, arms) ;
247269 check_wild_enum_match ( cx, ex, arms) ;
248270 check_match_as_ref ( cx, ex, arms, expr) ;
271+ check_wild_in_or_pats ( cx, arms) ;
249272 }
250273 if let ExprKind :: Match ( ref ex, ref arms, _) = expr. kind {
251274 check_match_ref_pats ( cx, ex, arms, expr) ;
@@ -664,6 +687,23 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>],
664687 }
665688}
666689
690+ fn check_wild_in_or_pats ( cx : & LateContext < ' _ , ' _ > , arms : & [ Arm < ' _ > ] ) {
691+ for arm in arms {
692+ if let PatKind :: Or ( ref fields) = arm. pat . kind {
693+ // look for multiple fields in this arm that contains at least one Wild pattern
694+ if fields. len ( ) > 1 && fields. iter ( ) . any ( is_wild) {
695+ span_help_and_lint (
696+ cx,
697+ WILDCARD_IN_OR_PATTERNS ,
698+ arm. pat . span ,
699+ "wildcard pattern covers any other pattern as it will match anyway." ,
700+ "Consider handling `_` separately." ,
701+ ) ;
702+ }
703+ }
704+ }
705+ }
706+
667707/// Gets all arms that are unbounded `PatRange`s.
668708fn all_ranges < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , arms : & ' tcx [ Arm < ' _ > ] ) -> Vec < SpannedRange < Constant > > {
669709 arms. iter ( )
0 commit comments