diff --git a/src/lints/enum_no_longer_non_exhaustive.ron b/src/lints/enum_no_longer_non_exhaustive.ron new file mode 100644 index 00000000..9008ca60 --- /dev/null +++ b/src/lints/enum_no_longer_non_exhaustive.ron @@ -0,0 +1,50 @@ +SemverQuery( + id: "enum_no_longer_non_exhaustive", + human_readable_name: "enum no longer #[non_exhaustive]", + description: "A pub enum is no longer #[non_exhaustive]. Pattern-matching outside its crate is now exhaustive, potentially causing breaking changes if new variants are added.", + required_update: Minor, + lint_level: Allow, + 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"]) @output + name @output + + attrs @filter(op: "not_contains", value: ["$non_exhaustive"]) + + importable_path { + path @output @tag + } + + span_: span @optional { + filename @output + begin_line @output + } + } + } + } + baseline { + item { + ... on Enum { + visibility_limit @filter(op: "=", value: ["$public"]) + attrs @filter(op: "contains", value: ["$non_exhaustive"]) + + importable_path { + path @filter(op: "=", value: ["%path"]) + } + } + } + } + } + }"#, + arguments: { + "public": "public", + "non_exhaustive": "#[non_exhaustive]", + }, + error_message: "A pub enum is no longer #[non_exhaustive]. Pattern-matching outside its crate is now exhaustive, potentially causing breaking changes if new variants are added.", + per_result_error_template: Some("enum {{name}} in {{span_filename}}:{{span_begin_line}}"), +) diff --git a/src/query.rs b/src/query.rs index 26590d71..dd33803d 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1232,6 +1232,7 @@ add_lints!( enum_marked_non_exhaustive, enum_missing, enum_must_use_added, + enum_no_longer_non_exhaustive, enum_no_repr_variant_discriminant_changed, enum_now_doc_hidden, enum_repr_int_changed, diff --git a/test_crates/enum_no_longer_non_exhaustive/new/Cargo.toml b/test_crates/enum_no_longer_non_exhaustive/new/Cargo.toml new file mode 100644 index 00000000..4dbb2138 --- /dev/null +++ b/test_crates/enum_no_longer_non_exhaustive/new/Cargo.toml @@ -0,0 +1,7 @@ +[package] +publish = false +name = "enum_no_longer_non_exhaustive" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test_crates/enum_no_longer_non_exhaustive/new/src/lib.rs b/test_crates/enum_no_longer_non_exhaustive/new/src/lib.rs new file mode 100644 index 00000000..4b4ac7e2 --- /dev/null +++ b/test_crates/enum_no_longer_non_exhaustive/new/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] + +pub enum NonExhaustiveEnum { + Variant, +} diff --git a/test_crates/enum_no_longer_non_exhaustive/old/Cargo.toml b/test_crates/enum_no_longer_non_exhaustive/old/Cargo.toml new file mode 100644 index 00000000..4dbb2138 --- /dev/null +++ b/test_crates/enum_no_longer_non_exhaustive/old/Cargo.toml @@ -0,0 +1,7 @@ +[package] +publish = false +name = "enum_no_longer_non_exhaustive" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test_crates/enum_no_longer_non_exhaustive/old/src/lib.rs b/test_crates/enum_no_longer_non_exhaustive/old/src/lib.rs new file mode 100644 index 00000000..1c410a7c --- /dev/null +++ b/test_crates/enum_no_longer_non_exhaustive/old/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] + +#[non_exhaustive] +pub enum NonExhaustiveEnum { + Variant, +} diff --git a/test_outputs/query_execution/enum_no_longer_non_exhaustive.snap b/test_outputs/query_execution/enum_no_longer_non_exhaustive.snap new file mode 100644 index 00000000..af4c9f10 --- /dev/null +++ b/test_outputs/query_execution/enum_no_longer_non_exhaustive.snap @@ -0,0 +1,42 @@ +--- +source: src/query.rs +expression: "&query_execution_results" +--- +{ + "./test_crates/enum_no_longer_non_exhaustive/": [ + { + "name": String("NonExhaustiveEnum"), + "path": List([ + String("enum_no_longer_non_exhaustive"), + String("NonExhaustiveEnum"), + ]), + "span_begin_line": Uint64(3), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + ], + "./test_crates/enum_repr_variant_discriminant_changed/": [ + { + "name": String("DiscriminantIsChangedButAVariantIsNonExhaustive"), + "path": List([ + String("enum_repr_variant_discriminant_changed"), + String("DiscriminantIsChangedButAVariantIsNonExhaustive"), + ]), + "span_begin_line": Uint64(23), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + ], + "./test_crates/type_mismatched_generic_lifetimes/": [ + { + "name": String("Either"), + "path": List([ + String("type_mismatched_generic_lifetimes"), + String("Either"), + ]), + "span_begin_line": Uint64(7), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + ], +}