diff options
| author | Devin Ragotzy <devin.ragotzy@gmail.com> | 2021-09-10 16:45:04 -0400 |
|---|---|---|
| committer | Devin Ragotzy <devin.ragotzy@gmail.com> | 2021-09-14 15:45:13 -0400 |
| commit | 33a06b73d90bde1d2fc4902672f4cbeb233b83e2 (patch) | |
| tree | f47c17d3d3eaf2020f7b02b4b9aabac7ffb2f999 /src | |
| parent | c3c0f80d6081092faff801542dd82f0e2420152b (diff) | |
| download | rust-33a06b73d90bde1d2fc4902672f4cbeb233b83e2.tar.gz rust-33a06b73d90bde1d2fc4902672f4cbeb233b83e2.zip | |
Add reachable_patterns lint to rfc-2008-non_exhaustive
Add linting on non_exhaustive structs and enum variants Add ui tests for non_exhaustive reachable lint Rename to non_exhaustive_omitted_patterns and avoid triggering on if let
Diffstat (limited to 'src')
5 files changed, 340 insertions, 5 deletions
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs index 8516bafef9b..0098f087d10 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs @@ -4,8 +4,29 @@ pub enum NonExhaustiveEnum { Unit, Tuple(u32), - Struct { field: u32 } + Struct { field: u32 }, +} + +#[non_exhaustive] +pub enum NestedNonExhaustive { + A(NonExhaustiveEnum), + B, + C, } #[non_exhaustive] pub enum EmptyNonExhaustiveEnum {} + +pub enum VariantNonExhaustive { + #[non_exhaustive] + Bar { + x: u32, + y: u64, + }, + Baz(u32, u16), +} + +#[non_exhaustive] +pub enum NonExhaustiveSingleVariant { + A(bool), +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs index 6bfe7bf923d..5b2181d2d83 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -1,3 +1,4 @@ +#[derive(Default)] #[non_exhaustive] pub struct NormalStruct { pub first_field: u16, @@ -15,7 +16,7 @@ pub struct TupleStruct(pub u16, pub u16); pub struct FunctionalRecord { pub first_field: u16, pub second_field: u16, - pub third_field: bool + pub third_field: bool, } impl Default for FunctionalRecord { @@ -23,3 +24,10 @@ impl Default for FunctionalRecord { FunctionalRecord { first_field: 640, second_field: 480, third_field: false } } } + +#[derive(Default)] +#[non_exhaustive] +pub struct NestedStruct { + pub foo: u16, + pub bar: NormalStruct, +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs new file mode 100644 index 00000000000..115fd300fa5 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs @@ -0,0 +1,160 @@ +// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly. + +// aux-build:enums.rs +extern crate enums; + +// aux-build:structs.rs +extern crate structs; + +use enums::{ + EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, + VariantNonExhaustive, +}; +use structs::{FunctionalRecord, NestedStruct, NormalStruct}; + +#[non_exhaustive] +#[derive(Default)] +pub struct Foo { + a: u8, + b: usize, + c: String, +} + +#[non_exhaustive] +pub enum Bar { + A, + B, + C, +} + +fn main() { + let enumeration = Bar::A; + + // Ok: this is a crate local non_exhaustive enum + match enumeration { + Bar::A => {} + Bar::B => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + let non_enum = NonExhaustiveEnum::Unit; + + // Ok: without the attribute + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } + + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + match non_enum { + NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + let x = 5; + match non_enum { + NonExhaustiveEnum::Unit if x > 10 => {} + NonExhaustiveEnum::Tuple(_) => {} + NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: all covered and not `unreachable-patterns` + #[deny(unreachable_patterns)] + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + NonExhaustiveEnum::Struct { .. } => {} + #[deny(non_exhaustive_omitted_patterns)] + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match NestedNonExhaustive::B { + NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} + NestedNonExhaustive::A(_) => {} + NestedNonExhaustive::B => {} + _ => {} + } + //~^^ some variants are not matched explicitly + //~^^^^^ some variants are not matched explicitly + + // The io::ErrorKind has many `unstable` fields how do they interact with this + // lint + #[deny(non_exhaustive_omitted_patterns)] + match std::io::ErrorKind::Other { + std::io::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 => {} + std::io::ErrorKind::Unsupported => {} + std::io::ErrorKind::OutOfMemory => {} + // All stable variants are above and unstable in `_` + _ => {} + } + //~^^ some variants are not matched explicitly + + #[warn(non_exhaustive_omitted_patterns)] + match VariantNonExhaustive::Baz(1, 2) { + VariantNonExhaustive::Baz(_, _) => {} + VariantNonExhaustive::Bar { x, .. } => {} + } + //~^^ some fields are not explicitly listed + + #[warn(non_exhaustive_omitted_patterns)] + let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); + //~^ some fields are not explicitly listed + + // Ok: this is local + #[warn(non_exhaustive_omitted_patterns)] + let Foo { a, b, .. } = Foo::default(); + + #[warn(non_exhaustive_omitted_patterns)] + let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + //~^ some fields are not explicitly listed + //~^^ some fields are not explicitly listed + + // Ok: because this only has 1 variant + #[deny(non_exhaustive_omitted_patterns)] + match NonExhaustiveSingleVariant::A(true) { + NonExhaustiveSingleVariant::A(true) => {} + _ => {} + } + + #[deny(non_exhaustive_omitted_patterns)] + match NonExhaustiveSingleVariant::A(true) { + _ => {} + } + //~^^ some variants are not matched explicitly + + // Ok: we don't lint on `if let` expressions + #[deny(non_exhaustive_omitted_patterns)] + if let NonExhaustiveEnum::Tuple(_) = non_enum {} +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr new file mode 100644 index 00000000000..aebe2acb6ad --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr @@ -0,0 +1,146 @@ +warning: some fields are not explicitly listed + --> $DIR/reachable-patterns.rs:127:9 + | +LL | VariantNonExhaustive::Bar { x, .. } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:124:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/reachable-patterns.rs:132:9 + | +LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:131:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/reachable-patterns.rs:140:29 + | +LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:139:12 + | +LL | #[warn(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found + +warning: some fields are not explicitly listed + --> $DIR/reachable-patterns.rs:140:9 + | +LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed + | + = help: ensure that all fields are mentioned explicitly by adding the suggested fields + = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:54:9 + | +LL | _ => {} + | ^ pattern `Struct { .. }` not covered + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:53:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:61:9 + | +LL | _ => {} + | ^ pattern `Tuple(_)` not covered + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:60:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:71:9 + | +LL | _ => {} + | ^ pattern `Unit` not covered + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:70:16 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:88:32 + | +LL | NestedNonExhaustive::A(_) => {} + | ^ patterns `Tuple(_)` and `Struct { .. }` not covered + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:85:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:90:9 + | +LL | _ => {} + | ^ pattern `C` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:120:9 + | +LL | _ => {} + | ^ patterns `HostUnreachable`, `NetworkUnreachable`, `NetworkDown` and 18 more not covered + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:97:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `ErrorKind` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/reachable-patterns.rs:153:9 + | +LL | _ => {} + | ^ pattern `A(_)` not covered + | +note: the lint level is defined here + --> $DIR/reachable-patterns.rs:151:12 + | +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found + +error: aborting due to 7 previous errors; 4 warnings emitted + diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr index b0c319f2c7f..272b2ef6ee1 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -16,13 +16,13 @@ error[E0603]: tuple struct constructor `TupleStruct` is private LL | let ts_explicit = structs::TupleStruct(640, 480); | ^^^^^^^^^^^ private tuple struct constructor | - ::: $DIR/auxiliary/structs.rs:11:24 + ::: $DIR/auxiliary/structs.rs:12:24 | LL | pub struct TupleStruct(pub u16, pub u16); | ---------------- a constructor is private if any of the fields is private | note: the tuple struct constructor `TupleStruct` is defined here - --> $DIR/auxiliary/structs.rs:11:1 + --> $DIR/auxiliary/structs.rs:12:1 | LL | pub struct TupleStruct(pub u16, pub u16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | let us_explicit = structs::UnitStruct; | ^^^^^^^^^^ private unit struct | note: the unit struct `UnitStruct` is defined here - --> $DIR/auxiliary/structs.rs:8:1 + --> $DIR/auxiliary/structs.rs:9:1 | LL | pub struct UnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^ |
