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
This commit is contained in:
parent
c3c0f80d60
commit
33a06b73d9
10 changed files with 626 additions and 68 deletions
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
160
src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs
Normal file
160
src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs
Normal file
|
|
@ -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 {}
|
||||
}
|
||||
146
src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr
Normal file
146
src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue