-
-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add lint
struct_marked_non_exhaustive_changed_type
(#963)
* implemented `struct_marked_non_exhaustive_changed_type` * reworded some comments * Apply suggestions from code review Co-authored-by: Predrag Gruevski <[email protected]> * renamed the lint to `non_exhaustive_struct_changed_type` * fixed the lints not being ordered correctly * fix: ran the testing --------- Co-authored-by: Predrag Gruevski <[email protected]>
- Loading branch information
1 parent
ad4552c
commit fb4ee17
Showing
10 changed files
with
209 additions
and
2 deletions.
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
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,74 @@ | ||
SemverQuery( | ||
id: "non_exhaustive_struct_changed_type", | ||
human_readable_name: "struct marked #[non_exhaustive] with no fields became an enum or union", | ||
description: "A struct marked #[non_exhaustive] with no fields was converted into an enum or union, breaking pattern matching.", | ||
required_update: Major, | ||
lint_level: Deny, | ||
reference_link: Some("https://internals.rust-lang.org/t/rest-patterns-foo-should-match-non-struct-types/21607"), | ||
reference: Some( | ||
r#"\ | ||
Even if a struct does not have fields and is marked `#[non_exhaustive]`, pattern matching like | ||
`matches!(value, Example { .. })` is allowed outside the struct's own crate. \ | ||
Changing such a struct into an enum or union will break such pattern matching. | ||
More info: https://github.com/obi1kenobi/cargo-semver-checks/issues/954 | ||
"# | ||
), | ||
query: r#" | ||
{ | ||
CrateDiff { | ||
baseline { | ||
item { | ||
... on Struct { | ||
struct_typename: __typename @tag @output | ||
visibility_limit @filter(op: "=", value: ["$public"]) @output | ||
struct_type @output | ||
# Requiring #[non_exhaustive] removes overlap with constructible_struct_changed_type | ||
attrs @filter(op: "contains", value: ["$non_exhaustive"]) | ||
# Requiring at least one field removes overlap with struct_with_no_pub_fields_changed_type | ||
# That this is not a special case in said query is a limitation of our query engine | ||
field @fold @transform(op: "count") @filter(op: "=", value: ["$zero"]) | ||
importable_path { | ||
path @output @tag | ||
public_api @filter(op: "=", value: ["$true"]) | ||
} | ||
} | ||
} | ||
} | ||
current { | ||
item { | ||
... on ImplOwner { | ||
current_typename: __typename @filter(op: "!=", value: ["%struct_typename"]) | ||
@output | ||
visibility_limit @filter(op: "=", value: ["$public"]) | ||
name @output | ||
importable_path { | ||
path @filter(op: "=", value: ["%path"]) | ||
public_api @filter(op: "=", value: ["$true"]) | ||
} | ||
span_: span @optional { | ||
filename @output | ||
begin_line @output | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}"#, | ||
arguments: { | ||
"public": "public", | ||
"non_exhaustive": "#[non_exhaustive]", | ||
"true": true, | ||
"zero": 0, | ||
}, | ||
error_message: "A struct marked #[non_exhaustive] with no fields was converted into an enum or union, breaking pattern matching", | ||
per_result_error_template: Some("struct {{join \"::\" path}} became {{lowercase current_typename}} in file {{span_filename}}:{{span_begin_line}}"), | ||
witness: ( | ||
hint_template: r#"matches!(value, {{join "::" path}} {..});"#, | ||
), | ||
) |
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
7 changes: 7 additions & 0 deletions
7
test_crates/non_exhaustive_struct_changed_type/new/Cargo.toml
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,7 @@ | ||
[package] | ||
publish = false | ||
name = "non_exhaustive_struct_changed_type" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
5 changes: 5 additions & 0 deletions
5
test_crates/non_exhaustive_struct_changed_type/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,5 @@ | ||
pub enum PubNonExhaustiveStructChangedToEnum {} | ||
|
||
pub union PubNonExhaustiveStructChangedToUnion { | ||
foo: usize | ||
} |
7 changes: 7 additions & 0 deletions
7
test_crates/non_exhaustive_struct_changed_type/old/Cargo.toml
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,7 @@ | ||
[package] | ||
publish = false | ||
name = "non_exhaustive_struct_changed_type" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
5 changes: 5 additions & 0 deletions
5
test_crates/non_exhaustive_struct_changed_type/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,5 @@ | ||
#[non_exhaustive] | ||
pub struct PubNonExhaustiveStructChangedToEnum {} | ||
|
||
#[non_exhaustive] | ||
pub struct PubNonExhaustiveStructChangedToUnion {} |
75 changes: 75 additions & 0 deletions
75
test_outputs/query_execution/non_exhaustive_struct_changed_type.snap
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 @@ | ||
--- | ||
source: src/query.rs | ||
expression: "&query_execution_results" | ||
--- | ||
{ | ||
"./test_crates/non_exhaustive_struct_changed_type/": [ | ||
{ | ||
"current_typename": String("Enum"), | ||
"name": String("PubNonExhaustiveStructChangedToEnum"), | ||
"path": List([ | ||
String("non_exhaustive_struct_changed_type"), | ||
String("PubNonExhaustiveStructChangedToEnum"), | ||
]), | ||
"span_begin_line": Uint64(1), | ||
"span_filename": String("src/lib.rs"), | ||
"struct_type": String("plain"), | ||
"struct_typename": String("Struct"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"current_typename": String("Union"), | ||
"name": String("PubNonExhaustiveStructChangedToUnion"), | ||
"path": List([ | ||
String("non_exhaustive_struct_changed_type"), | ||
String("PubNonExhaustiveStructChangedToUnion"), | ||
]), | ||
"span_begin_line": Uint64(3), | ||
"span_filename": String("src/lib.rs"), | ||
"struct_type": String("plain"), | ||
"struct_typename": String("Struct"), | ||
"visibility_limit": String("public"), | ||
}, | ||
], | ||
"./test_crates/struct_becomes_enum/": [ | ||
{ | ||
"current_typename": String("Enum"), | ||
"name": String("NonExhaustiveEmptyStructToEnum"), | ||
"path": List([ | ||
String("struct_becomes_enum"), | ||
String("NonExhaustiveEmptyStructToEnum"), | ||
]), | ||
"span_begin_line": Uint64(82), | ||
"span_filename": String("src/lib.rs"), | ||
"struct_type": String("plain"), | ||
"struct_typename": String("Struct"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"current_typename": String("Enum"), | ||
"name": String("NonExhaustiveFieldlessUnit"), | ||
"path": List([ | ||
String("struct_becomes_enum"), | ||
String("NonExhaustiveFieldlessUnit"), | ||
]), | ||
"span_begin_line": Uint64(95), | ||
"span_filename": String("src/lib.rs"), | ||
"struct_type": String("unit"), | ||
"struct_typename": String("Struct"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"current_typename": String("Enum"), | ||
"name": String("NonExhaustiveFieldlessTuple"), | ||
"path": List([ | ||
String("struct_becomes_enum"), | ||
String("NonExhaustiveFieldlessTuple"), | ||
]), | ||
"span_begin_line": Uint64(100), | ||
"span_filename": String("src/lib.rs"), | ||
"struct_type": String("tuple"), | ||
"struct_typename": String("Struct"), | ||
"visibility_limit": String("public"), | ||
}, | ||
], | ||
} |
29 changes: 29 additions & 0 deletions
29
test_outputs/witnesses/non_exhaustive_struct_changed_type.snap
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,29 @@ | ||
--- | ||
source: src/query.rs | ||
description: "Lint `non_exhaustive_struct_changed_type` did not have the expected witness output.\nSee https://github.com/obi1kenobi/cargo-semver-checks/blob/main/CONTRIBUTING.md#testing-witnesses\nfor more information." | ||
expression: "&actual_witnesses" | ||
--- | ||
[["./test_crates/non_exhaustive_struct_changed_type/"]] | ||
filename = 'src/lib.rs' | ||
begin_line = 1 | ||
hint = 'matches!(value, non_exhaustive_struct_changed_type::PubNonExhaustiveStructChangedToEnum {..});' | ||
|
||
[["./test_crates/non_exhaustive_struct_changed_type/"]] | ||
filename = 'src/lib.rs' | ||
begin_line = 3 | ||
hint = 'matches!(value, non_exhaustive_struct_changed_type::PubNonExhaustiveStructChangedToUnion {..});' | ||
|
||
[["./test_crates/struct_becomes_enum/"]] | ||
filename = 'src/lib.rs' | ||
begin_line = 82 | ||
hint = 'matches!(value, struct_becomes_enum::NonExhaustiveEmptyStructToEnum {..});' | ||
|
||
[["./test_crates/struct_becomes_enum/"]] | ||
filename = 'src/lib.rs' | ||
begin_line = 95 | ||
hint = 'matches!(value, struct_becomes_enum::NonExhaustiveFieldlessUnit {..});' | ||
|
||
[["./test_crates/struct_becomes_enum/"]] | ||
filename = 'src/lib.rs' | ||
begin_line = 100 | ||
hint = 'matches!(value, struct_becomes_enum::NonExhaustiveFieldlessTuple {..});' |