@@ -3,7 +3,8 @@ use crate::utils::paths;
3
3
use crate :: utils:: sugg:: Sugg ;
4
4
use crate :: utils:: {
5
5
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,
7
8
} ;
8
9
use if_chain:: if_chain;
9
10
use rustc:: declare_lint_pass;
@@ -223,6 +224,26 @@ declare_clippy_lint! {
223
224
"a wildcard enum match arm using `_`"
224
225
}
225
226
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
+
226
247
declare_lint_pass ! ( Matches => [
227
248
SINGLE_MATCH ,
228
249
MATCH_REF_PATS ,
@@ -231,7 +252,8 @@ declare_lint_pass!(Matches => [
231
252
MATCH_OVERLAPPING_ARM ,
232
253
MATCH_WILD_ERR_ARM ,
233
254
MATCH_AS_REF ,
234
- WILDCARD_ENUM_MATCH_ARM
255
+ WILDCARD_ENUM_MATCH_ARM ,
256
+ WILDCARD_IN_OR_PATTERNS
235
257
] ) ;
236
258
237
259
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Matches {
@@ -246,6 +268,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
246
268
check_wild_err_arm ( cx, ex, arms) ;
247
269
check_wild_enum_match ( cx, ex, arms) ;
248
270
check_match_as_ref ( cx, ex, arms, expr) ;
271
+ check_wild_in_or_pats ( cx, arms) ;
249
272
}
250
273
if let ExprKind :: Match ( ref ex, ref arms, _) = expr. kind {
251
274
check_match_ref_pats ( cx, ex, arms, expr) ;
@@ -664,6 +687,23 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>],
664
687
}
665
688
}
666
689
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
+
667
707
/// Gets all arms that are unbounded `PatRange`s.
668
708
fn all_ranges < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , arms : & ' tcx [ Arm < ' _ > ] ) -> Vec < SpannedRange < Constant > > {
669
709
arms. iter ( )
0 commit comments