From c21b4ad7d46118c1fd0747b52dd3f052aee79021 Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Sun, 22 Dec 2019 02:13:39 +0000 Subject: [PATCH] Update wildcard enum match lint for non_exhaustive enums --- clippy_lints/src/matches.rs | 13 ++++++++-- tests/ui/wildcard_enum_match_arm.fixed | 32 ++++++++++++++++++++++++- tests/ui/wildcard_enum_match_arm.rs | 32 ++++++++++++++++++++++++- tests/ui/wildcard_enum_match_arm.stderr | 16 +++++++++---- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index cf7650d02..4c4a64f4a 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -522,7 +522,7 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) { } } - let suggestion: Vec = missing_variants + let mut suggestion: Vec = missing_variants .iter() .map(|v| { let suffix = match v.ctor_kind { @@ -543,11 +543,20 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) { return; } + let mut message = "wildcard match will miss any future added variants."; + + if let ty::Adt(def, _) = ty.kind { + if def.is_variant_list_non_exhaustive() { + message = "match on non-exhaustive enum doesn't explicitly match all known variants."; + suggestion.push(String::from("_")); + } + } + span_lint_and_sugg( cx, WILDCARD_ENUM_MATCH_ARM, wildcard_span, - "wildcard match will miss any future added variants.", + message, "try this", suggestion.join(" | "), Applicability::MachineApplicable, diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index af67f326f..1da2833e2 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -1,7 +1,9 @@ // run-rustfix #![deny(clippy::wildcard_enum_match_arm)] -#![allow(unreachable_code, unused_variables, dead_code)] +#![allow(unreachable_code, unused_variables, dead_code, clippy::single_match)] + +use std::io::ErrorKind; #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum Color { @@ -62,4 +64,32 @@ fn main() { 140 => {}, _ => {}, }; + // We need to use an enum not defined in this test because non_exhaustive is ignored for the + // purposes of dead code analysis within a crate. + let error_kind = ErrorKind::NotFound; + match error_kind { + ErrorKind::NotFound => {}, + std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _ => {}, + } + match error_kind { + ErrorKind::NotFound => {}, + ErrorKind::PermissionDenied => {}, + ErrorKind::ConnectionRefused => {}, + ErrorKind::ConnectionReset => {}, + ErrorKind::ConnectionAborted => {}, + ErrorKind::NotConnected => {}, + ErrorKind::AddrInUse => {}, + ErrorKind::AddrNotAvailable => {}, + ErrorKind::BrokenPipe => {}, + ErrorKind::AlreadyExists => {}, + ErrorKind::WouldBlock => {}, + ErrorKind::InvalidInput => {}, + ErrorKind::InvalidData => {}, + ErrorKind::TimedOut => {}, + ErrorKind::WriteZero => {}, + ErrorKind::Interrupted => {}, + ErrorKind::Other => {}, + ErrorKind::UnexpectedEof => {}, + _ => {}, + } } diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index 049596d34..c2eb4b308 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -1,7 +1,9 @@ // run-rustfix #![deny(clippy::wildcard_enum_match_arm)] -#![allow(unreachable_code, unused_variables, dead_code)] +#![allow(unreachable_code, unused_variables, dead_code, clippy::single_match)] + +use std::io::ErrorKind; #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum Color { @@ -62,4 +64,32 @@ fn main() { 140 => {}, _ => {}, }; + // We need to use an enum not defined in this test because non_exhaustive is ignored for the + // purposes of dead code analysis within a crate. + let error_kind = ErrorKind::NotFound; + match error_kind { + ErrorKind::NotFound => {}, + _ => {}, + } + match error_kind { + ErrorKind::NotFound => {}, + ErrorKind::PermissionDenied => {}, + ErrorKind::ConnectionRefused => {}, + ErrorKind::ConnectionReset => {}, + ErrorKind::ConnectionAborted => {}, + ErrorKind::NotConnected => {}, + ErrorKind::AddrInUse => {}, + ErrorKind::AddrNotAvailable => {}, + ErrorKind::BrokenPipe => {}, + ErrorKind::AlreadyExists => {}, + ErrorKind::WouldBlock => {}, + ErrorKind::InvalidInput => {}, + ErrorKind::InvalidData => {}, + ErrorKind::TimedOut => {}, + ErrorKind::WriteZero => {}, + ErrorKind::Interrupted => {}, + ErrorKind::Other => {}, + ErrorKind::UnexpectedEof => {}, + _ => {}, + } } diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index df90bad15..1020542c1 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -1,5 +1,5 @@ error: wildcard match will miss any future added variants. - --> $DIR/wildcard_enum_match_arm.rs:29:9 + --> $DIR/wildcard_enum_match_arm.rs:31:9 | LL | _ => eprintln!("Not red"), | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` @@ -11,22 +11,28 @@ LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wildcard match will miss any future added variants. - --> $DIR/wildcard_enum_match_arm.rs:33:9 + --> $DIR/wildcard_enum_match_arm.rs:35:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will miss any future added variants. - --> $DIR/wildcard_enum_match_arm.rs:37:9 + --> $DIR/wildcard_enum_match_arm.rs:39:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will miss any future added variants. - --> $DIR/wildcard_enum_match_arm.rs:53:9 + --> $DIR/wildcard_enum_match_arm.rs:55:9 | LL | _ => "No red", | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` -error: aborting due to 4 previous errors +error: match on non-exhaustive enum doesn't explicitly match all known variants. + --> $DIR/wildcard_enum_match_arm.rs:72:9 + | +LL | _ => {}, + | ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _` + +error: aborting due to 5 previous errors