@@ -220,7 +220,7 @@ declare_clippy_lint! {
220
220
/// # enum Foo { A(usize), B(usize) }
221
221
/// # let x = Foo::B(1);
222
222
/// match x {
223
- /// A => {},
223
+ /// Foo::A(_) => {},
224
224
/// _ => {},
225
225
/// }
226
226
/// ```
@@ -229,6 +229,40 @@ declare_clippy_lint! {
229
229
"a wildcard enum match arm using `_`"
230
230
}
231
231
232
+ declare_clippy_lint ! {
233
+ /// **What it does:** Checks for wildcard enum matches for a single variant.
234
+ ///
235
+ /// **Why is this bad?** New enum variants added by library updates can be missed.
236
+ ///
237
+ /// **Known problems:** Suggested replacements may not use correct path to enum
238
+ /// if it's not present in the current scope.
239
+ ///
240
+ /// **Example:**
241
+ ///
242
+ /// ```rust
243
+ /// # enum Foo { A, B, C }
244
+ /// # let x = Foo::B;
245
+ /// match x {
246
+ /// Foo::A => {},
247
+ /// Foo::B => {},
248
+ /// _ => {},
249
+ /// }
250
+ /// ```
251
+ /// Use instead:
252
+ /// ```rust
253
+ /// # enum Foo { A, B, C }
254
+ /// # let x = Foo::B;
255
+ /// match x {
256
+ /// Foo::A => {},
257
+ /// Foo::B => {},
258
+ /// Foo::C => {},
259
+ /// }
260
+ /// ```
261
+ pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS ,
262
+ pedantic,
263
+ "a wildcard enum match for a single variant"
264
+ }
265
+
232
266
declare_clippy_lint ! {
233
267
/// **What it does:** Checks for wildcard pattern used with others patterns in same match arm.
234
268
///
@@ -356,6 +390,7 @@ impl_lint_pass!(Matches => [
356
390
MATCH_WILD_ERR_ARM ,
357
391
MATCH_AS_REF ,
358
392
WILDCARD_ENUM_MATCH_ARM ,
393
+ MATCH_WILDCARD_FOR_SINGLE_VARIANTS ,
359
394
WILDCARD_IN_OR_PATTERNS ,
360
395
MATCH_SINGLE_BINDING ,
361
396
INFALLIBLE_DESTRUCTURING_MATCH ,
@@ -729,9 +764,21 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_
729
764
if let QPath :: Resolved ( _, p) = path {
730
765
missing_variants. retain ( |e| e. ctor_def_id != Some ( p. res . def_id ( ) ) ) ;
731
766
}
732
- } else if let PatKind :: TupleStruct ( ref path, ..) = arm. pat . kind {
767
+ } else if let PatKind :: TupleStruct ( ref path, ref patterns , ..) = arm. pat . kind {
733
768
if let QPath :: Resolved ( _, p) = path {
734
- missing_variants. retain ( |e| e. ctor_def_id != Some ( p. res . def_id ( ) ) ) ;
769
+ // Some simple checks for exhaustive patterns.
770
+ // There is a room for improvements to detect more cases,
771
+ // but it can be more expensive to do so.
772
+ let is_pattern_exhaustive = |pat : & & Pat < ' _ > | {
773
+ if let PatKind :: Wild | PatKind :: Binding ( .., None ) = pat. kind {
774
+ true
775
+ } else {
776
+ false
777
+ }
778
+ } ;
779
+ if patterns. iter ( ) . all ( is_pattern_exhaustive) {
780
+ missing_variants. retain ( |e| e. ctor_def_id != Some ( p. res . def_id ( ) ) ) ;
781
+ }
735
782
}
736
783
}
737
784
}
@@ -766,14 +813,27 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_
766
813
}
767
814
}
768
815
816
+ if suggestion. len ( ) == 1 {
817
+ // No need to check for non-exhaustive enum as in that case len would be greater than 1
818
+ span_lint_and_sugg (
819
+ cx,
820
+ MATCH_WILDCARD_FOR_SINGLE_VARIANTS ,
821
+ wildcard_span,
822
+ message,
823
+ "try this" ,
824
+ suggestion[ 0 ] . clone ( ) ,
825
+ Applicability :: MaybeIncorrect ,
826
+ )
827
+ } ;
828
+
769
829
span_lint_and_sugg (
770
830
cx,
771
831
WILDCARD_ENUM_MATCH_ARM ,
772
832
wildcard_span,
773
833
message,
774
834
"try this" ,
775
835
suggestion. join ( " | " ) ,
776
- Applicability :: MachineApplicable ,
836
+ Applicability :: MaybeIncorrect ,
777
837
)
778
838
}
779
839
}
0 commit comments