-
-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add lint for exhaustive struct variants gaining new fields. (#238)
- Loading branch information
1 parent
74129da
commit d71f852
Showing
8 changed files
with
184 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
SemverQuery( | ||
id: "enum_struct_variant_field_added", | ||
human_readable_name: "pub enum struct variant field added", | ||
description: "An enum's exhaustive struct variant has a new field.", | ||
required_update: Major, | ||
reference_link: Some("https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute"), | ||
query: r#" | ||
{ | ||
CrateDiff { | ||
current { | ||
item { | ||
... on Enum { | ||
visibility_limit @filter(op: "=", value: ["$public"]) | ||
enum_name: name @output @tag | ||
importable_path { | ||
path @output @tag | ||
} | ||
variant { | ||
... on StructVariant { | ||
# If the variant is now marked `#[non_exhaustive]`, | ||
# that's already a breaking change that has its own rule. | ||
# Don't also report new field additions, since the programmer has | ||
# clearly stated that they don't consider it exhaustive anymore. | ||
attrs @filter(op: "not_contains", value: ["$non_exhaustive"]) | ||
variant_name: name @output @tag | ||
field { | ||
field_name: name @output @tag | ||
span_: span @optional { | ||
filename @output | ||
begin_line @output | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
baseline { | ||
item { | ||
... on Enum { | ||
visibility_limit @filter(op: "=", value: ["$public"]) | ||
name @filter(op: "=", value: ["%enum_name"]) | ||
importable_path { | ||
path @filter(op: "=", value: ["%path"]) | ||
} | ||
variant { | ||
... on StructVariant { | ||
name @filter(op: "=", value: ["%variant_name"]) | ||
attrs @filter(op: "not_contains", value: ["$non_exhaustive"]) | ||
field @fold @transform(op: "count") @filter(op: "=", value: ["$zero"]) { | ||
name @filter(op: "=", value: ["%field_name"]) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}"#, | ||
arguments: { | ||
"public": "public", | ||
"zero": 0, | ||
"non_exhaustive": "#[non_exhaustive]", | ||
}, | ||
error_message: "An enum's exhaustive struct variant has a new field, which has to be included when constructing or matching on this variant.", | ||
per_result_error_template: Some("field {{field_name}} of variant {{enum_name}}::{{variant_name}} in {{span_filename}}:{{span_begin_line}}"), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[package] | ||
name = "enum_struct_variant_field_added" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
36 changes: 36 additions & 0 deletions
36
test_crates/enum_struct_variant_field_added/new/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
pub enum PubEnum { | ||
Foo { | ||
x: i64, | ||
y: usize, | ||
} | ||
} | ||
|
||
// This enum is not public, so it should not be reported by the lint, | ||
// regardless of the new field in the variant. | ||
pub(crate) enum PrivateEnum { | ||
Foo { | ||
x: i64, | ||
y: usize, | ||
} | ||
} | ||
|
||
// This enum's variant is non-exhaustive, so it can't be externally constructed | ||
// and can't be matched on without a `..`, and therefore should not be reported by the lint, | ||
// regardless of the new field in the variant. | ||
pub enum EnumWithNonExhaustiveVariant { | ||
#[non_exhaustive] | ||
Variant { | ||
x: i64, | ||
y: usize, | ||
} | ||
} | ||
|
||
// This enum's variant will become non-exhaustive while also gaining a field. | ||
// That should trigger a separate lint, and not this one. | ||
pub enum EnumWithExhaustiveVariant { | ||
#[non_exhaustive] | ||
ExhaustiveVariant { | ||
x: i64, | ||
y: usize, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[package] | ||
name = "enum_struct_variant_field_added" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
31 changes: 31 additions & 0 deletions
31
test_crates/enum_struct_variant_field_added/old/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
pub enum PubEnum { | ||
Foo { | ||
x: i64, | ||
} | ||
} | ||
|
||
// This enum is not public, so it should not be reported by the lint, | ||
// regardless of the new field in the variant. | ||
pub(crate) enum PrivateEnum { | ||
Foo { | ||
x: i64, | ||
} | ||
} | ||
|
||
// This enum's variant is non-exhaustive, so it can't be externally constructed | ||
// and can't be matched on without a `..`, and therefore should not be reported by the lint, | ||
// regardless of the new field in the variant. | ||
pub enum EnumWithNonExhaustiveVariant { | ||
#[non_exhaustive] | ||
Variant { | ||
x: i64, | ||
} | ||
} | ||
|
||
// This enum's variant will become non-exhaustive while also gaining a field. | ||
// That should trigger a separate lint, and not this one. | ||
pub enum EnumWithExhaustiveVariant { | ||
ExhaustiveVariant { | ||
x: i64, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"./test_crates/enum_struct_variant_field_added/": [ | ||
{ | ||
"enum_name": String("PubEnum"), | ||
"field_name": String("y"), | ||
"path": List([ | ||
String("enum_struct_variant_field_added"), | ||
String("PubEnum"), | ||
]), | ||
"span_begin_line": Uint64(4), | ||
"span_filename": String("src/lib.rs"), | ||
"variant_name": String("Foo"), | ||
}, | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters