diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2021-01-21 13:41:57 -0800 |
|---|---|---|
| committer | Manish Goregaokar <manishsmail@gmail.com> | 2021-01-22 11:59:36 -0800 |
| commit | 8cb7e85006853e99e6ba2bf378c801fb53eee8fa (patch) | |
| tree | 5388c115b64ba03d5d712a5f55a228cdddc28037 | |
| parent | 09d4d49299c6614a0ae956980e709a234d21a9ef (diff) | |
| download | rust-8cb7e85006853e99e6ba2bf378c801fb53eee8fa.tar.gz rust-8cb7e85006853e99e6ba2bf378c801fb53eee8fa.zip | |
Add exhaustive_structs lint
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | clippy_lints/src/exhaustive_items.rs | 54 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | tests/ui/exhaustive_items.fixed | 86 | ||||
| -rw-r--r-- | tests/ui/exhaustive_items.rs | 85 | ||||
| -rw-r--r-- | tests/ui/exhaustive_items.stderr | 52 |
6 files changed, 199 insertions, 81 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cf2125ea2f..ccc7eb7e881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1939,6 +1939,7 @@ Released 2018-09-13 [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision [`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums +[`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs [`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit [`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call [`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 0fa6c4b589f..d604ad0004f 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -1,7 +1,7 @@ use crate::utils::{snippet_opt, span_lint_and_help, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_hir::{Item, ItemKind}; use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -10,7 +10,8 @@ declare_clippy_lint! { /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` /// /// **Why is this bad?** Exhaustive enums are typically fine, but a project which does - /// not wish to make a stability commitment around enums may wish to disable them by default. + /// not wish to make a stability commitment around exported enums may wish to + /// disable them by default. /// /// **Known problems:** None. /// @@ -28,25 +29,62 @@ declare_clippy_lint! { /// enum Foo { /// Bar, /// Baz - /// } /// ``` + /// } + /// ``` pub EXHAUSTIVE_ENUMS, restriction, - "default lint description" + "detects exported enums that have not been marked #[non_exhaustive]" +} + +declare_clippy_lint! { + /// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` + /// + /// **Why is this bad?** Exhaustive structs are typically fine, but a project which does + /// not wish to make a stability commitment around exported structs may wish to + /// disable them by default. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// struct Foo { + /// bar: u8, + /// baz: String, + /// } + /// ``` + /// Use instead: + /// ```rust + /// #[non_exhaustive] + /// struct Foo { + /// bar: u8, + /// baz: String, + /// } + /// ``` + pub EXHAUSTIVE_STRUCTS, + restriction, + "detects exported structs that have not been marked #[non_exhaustive]" } -declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS]); +declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]); impl LateLintPass<'_> for ExhaustiveItems { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if_chain! { - if let ItemKind::Enum(..) = item.kind; + if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind; if cx.access_levels.is_exported(item.hir_id); if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive)); then { + let lint = if let ItemKind::Enum(..) = item.kind { + EXHAUSTIVE_ENUMS + } else { + EXHAUSTIVE_STRUCTS + }; + if let Some(snippet) = snippet_opt(cx, item.span) { span_lint_and_sugg( cx, - EXHAUSTIVE_ENUMS, + lint, item.span, "enums should not be exhaustive", "try adding #[non_exhaustive]", @@ -56,7 +94,7 @@ impl LateLintPass<'_> for ExhaustiveItems { } else { span_lint_and_help( cx, - EXHAUSTIVE_ENUMS, + lint, item.span, "enums should not be exhaustive", None, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a5deebf7d5f..91c74026f64 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -613,6 +613,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, &excessive_bools::STRUCT_EXCESSIVE_BOOLS, &exhaustive_items::EXHAUSTIVE_ENUMS, + &exhaustive_items::EXHAUSTIVE_STRUCTS, &exit::EXIT, &explicit_write::EXPLICIT_WRITE, &fallible_impl_from::FALLIBLE_IMPL_FROM, @@ -1250,6 +1251,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS), + LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS), LintId::of(&exit::EXIT), LintId::of(&float_literal::LOSSY_FLOAT_LITERAL), LintId::of(&implicit_return::IMPLICIT_RETURN), diff --git a/tests/ui/exhaustive_items.fixed b/tests/ui/exhaustive_items.fixed index 71c4a251e3b..bc146c6afc5 100644 --- a/tests/ui/exhaustive_items.fixed +++ b/tests/ui/exhaustive_items.fixed @@ -1,42 +1,72 @@ // run-rustfix -#![deny(clippy::exhaustive_enums)] +#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] fn main() { // nop } -#[non_exhaustive] +pub mod enums { + #[non_exhaustive] pub enum Exhaustive { - Foo, - Bar, - Baz, - Quux(String), -} + Foo, + Bar, + Baz, + Quux(String), + } -// no warning, already non_exhaustive -#[non_exhaustive] -pub enum NonExhaustive { - Foo, - Bar, - Baz, - Quux(String), -} + // no warning, already non_exhaustive + #[non_exhaustive] + pub enum NonExhaustive { + Foo, + Bar, + Baz, + Quux(String), + } + + // no warning, private + enum ExhaustivePrivate { + Foo, + Bar, + Baz, + Quux(String), + } -// no warning, private -enum ExhaustivePrivate { - Foo, - Bar, - Baz, - Quux(String), + // no warning, private + #[non_exhaustive] + enum NonExhaustivePrivate { + Foo, + Bar, + Baz, + Quux(String), + } } -// no warning, private -#[non_exhaustive] -enum NonExhaustivePrivate { - Foo, - Bar, - Baz, - Quux(String), +pub mod structs { + #[non_exhaustive] +pub struct Exhaustive { + foo: u8, + bar: String, + } + + // no warning, already non_exhaustive + #[non_exhaustive] + pub struct NonExhaustive { + foo: u8, + bar: String, + } + + // no warning, private + struct ExhaustivePrivate { + foo: u8, + bar: String, + } + + // no warning, private + #[non_exhaustive] + struct NonExhaustivePrivate { + foo: u8, + bar: String, + } } diff --git a/tests/ui/exhaustive_items.rs b/tests/ui/exhaustive_items.rs index 45af6851dd1..ed86b50be30 100644 --- a/tests/ui/exhaustive_items.rs +++ b/tests/ui/exhaustive_items.rs @@ -1,41 +1,70 @@ // run-rustfix -#![deny(clippy::exhaustive_enums)] +#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] fn main() { // nop } -pub enum Exhaustive { - Foo, - Bar, - Baz, - Quux(String), -} +pub mod enums { + pub enum Exhaustive { + Foo, + Bar, + Baz, + Quux(String), + } -// no warning, already non_exhaustive -#[non_exhaustive] -pub enum NonExhaustive { - Foo, - Bar, - Baz, - Quux(String), -} + // no warning, already non_exhaustive + #[non_exhaustive] + pub enum NonExhaustive { + Foo, + Bar, + Baz, + Quux(String), + } + + // no warning, private + enum ExhaustivePrivate { + Foo, + Bar, + Baz, + Quux(String), + } -// no warning, private -enum ExhaustivePrivate { - Foo, - Bar, - Baz, - Quux(String), + // no warning, private + #[non_exhaustive] + enum NonExhaustivePrivate { + Foo, + Bar, + Baz, + Quux(String), + } } -// no warning, private -#[non_exhaustive] -enum NonExhaustivePrivate { - Foo, - Bar, - Baz, - Quux(String), +pub mod structs { + pub struct Exhaustive { + foo: u8, + bar: String, + } + + // no warning, already non_exhaustive + #[non_exhaustive] + pub struct NonExhaustive { + foo: u8, + bar: String, + } + + // no warning, private + struct ExhaustivePrivate { + foo: u8, + bar: String, + } + + // no warning, private + #[non_exhaustive] + struct NonExhaustivePrivate { + foo: u8, + bar: String, + } } diff --git a/tests/ui/exhaustive_items.stderr b/tests/ui/exhaustive_items.stderr index d00d950efc7..7e286e65949 100644 --- a/tests/ui/exhaustive_items.stderr +++ b/tests/ui/exhaustive_items.stderr @@ -1,28 +1,46 @@ error: enums should not be exhaustive - --> $DIR/exhaustive_items.rs:10:1 + --> $DIR/exhaustive_items.rs:11:5 | -LL | / pub enum Exhaustive { -LL | | Foo, -LL | | Bar, -LL | | Baz, -LL | | Quux(String), -LL | | } - | |_^ +LL | / pub enum Exhaustive { +LL | | Foo, +LL | | Bar, +LL | | Baz, +LL | | Quux(String), +LL | | } + | |_____^ | note: the lint level is defined here - --> $DIR/exhaustive_items.rs:3:9 + --> $DIR/exhaustive_items.rs:3:35 | -LL | #![deny(clippy::exhaustive_enums)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try adding #[non_exhaustive] | -LL | #[non_exhaustive] +LL | #[non_exhaustive] LL | pub enum Exhaustive { -LL | Foo, -LL | Bar, -LL | Baz, -LL | Quux(String), +LL | Foo, +LL | Bar, +LL | Baz, +LL | Quux(String), ... -error: aborting due to previous error +error: enums should not be exhaustive + --> $DIR/exhaustive_items.rs:46:5 + | +LL | / pub struct Exhaustive { +LL | | foo: u8, +LL | | bar: String, +LL | | } + | |_____^ + | +help: try adding #[non_exhaustive] + | +LL | #[non_exhaustive] +LL | pub struct Exhaustive { +LL | foo: u8, +LL | bar: String, +LL | } + | + +error: aborting due to 2 previous errors |
