New lint: exhaustive_enums

This commit is contained in:
Manish Goregaokar 2021-01-21 12:48:30 -08:00
parent 043cf97abc
commit f1ab3024b2
6 changed files with 148 additions and 0 deletions

View file

@ -1938,6 +1938,7 @@ Released 2018-09-13
[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`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 [`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
[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit [`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_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 [`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used

View file

@ -0,0 +1,68 @@
use crate::utils::{snippet_opt, span_lint_and_help, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::ast::{Item, ItemKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// **What it does:** Warns on any `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.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// enum Foo {
/// Bar,
/// Baz
/// }
/// ```
/// Use instead:
/// ```rust
/// #[non_exhaustive]
/// enum Foo {
/// Bar,
/// Baz
/// } /// ```
pub EXHAUSTIVE_ENUMS,
restriction,
"default lint description"
}
declare_lint_pass!(ExhaustiveEnums => [EXHAUSTIVE_ENUMS]);
impl EarlyLintPass for ExhaustiveEnums {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if_chain! {
if let ItemKind::Enum(..) = item.kind;
if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
then {
if let Some(snippet) = snippet_opt(cx, item.span) {
span_lint_and_sugg(
cx,
EXHAUSTIVE_ENUMS,
item.span,
"enums should not be exhaustive",
"try adding #[non_exhaustive]",
format!("#[non_exhaustive]\n{}", snippet),
Applicability::MaybeIncorrect,
);
} else {
span_lint_and_help(
cx,
EXHAUSTIVE_ENUMS,
item.span,
"enums should not be exhaustive",
None,
"try adding #[non_exhaustive]",
);
}
}
}
}
}

View file

@ -200,6 +200,7 @@ mod escape;
mod eta_reduction; mod eta_reduction;
mod eval_order_dependence; mod eval_order_dependence;
mod excessive_bools; mod excessive_bools;
mod exhaustive_enums;
mod exit; mod exit;
mod explicit_write; mod explicit_write;
mod fallible_impl_from; mod fallible_impl_from;
@ -611,6 +612,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&eval_order_dependence::EVAL_ORDER_DEPENDENCE, &eval_order_dependence::EVAL_ORDER_DEPENDENCE,
&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
&excessive_bools::STRUCT_EXCESSIVE_BOOLS, &excessive_bools::STRUCT_EXCESSIVE_BOOLS,
&exhaustive_enums::EXHAUSTIVE_ENUMS,
&exit::EXIT, &exit::EXIT,
&explicit_write::EXPLICIT_WRITE, &explicit_write::EXPLICIT_WRITE,
&fallible_impl_from::FALLIBLE_IMPL_FROM, &fallible_impl_from::FALLIBLE_IMPL_FROM,
@ -1096,6 +1098,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence); store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
store.register_late_pass(|| box missing_doc::MissingDoc::new()); store.register_late_pass(|| box missing_doc::MissingDoc::new());
store.register_late_pass(|| box missing_inline::MissingInline); store.register_late_pass(|| box missing_inline::MissingInline);
store.register_early_pass(move || box exhaustive_enums::ExhaustiveEnums);
store.register_late_pass(|| box if_let_some_result::OkIfLet); store.register_late_pass(|| box if_let_some_result::OkIfLet);
store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
@ -1246,6 +1249,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&create_dir::CREATE_DIR), LintId::of(&create_dir::CREATE_DIR),
LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&dbg_macro::DBG_MACRO),
LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
LintId::of(&exhaustive_enums::EXHAUSTIVE_ENUMS),
LintId::of(&exit::EXIT), LintId::of(&exit::EXIT),
LintId::of(&float_literal::LOSSY_FLOAT_LITERAL), LintId::of(&float_literal::LOSSY_FLOAT_LITERAL),
LintId::of(&implicit_return::IMPLICIT_RETURN), LintId::of(&implicit_return::IMPLICIT_RETURN),

View file

@ -0,0 +1,24 @@
// run-rustfix
#![deny(clippy::exhaustive_enums)]
#![allow(unused)]
fn main() {
// nop
}
#[non_exhaustive]
enum Exhaustive {
Foo,
Bar,
Baz,
Quux(String),
}
#[non_exhaustive]
enum NonExhaustive {
Foo,
Bar,
Baz,
Quux(String),
}

View file

@ -0,0 +1,23 @@
// run-rustfix
#![deny(clippy::exhaustive_enums)]
#![allow(unused)]
fn main() {
// nop
}
enum Exhaustive {
Foo,
Bar,
Baz,
Quux(String),
}
#[non_exhaustive]
enum NonExhaustive {
Foo,
Bar,
Baz,
Quux(String),
}

View file

@ -0,0 +1,28 @@
error: enums should not be exhaustive
--> $DIR/exhaustive_enums.rs:10:1
|
LL | / enum Exhaustive {
LL | | Foo,
LL | | Bar,
LL | | Baz,
LL | | Quux(String),
LL | | }
| |_^
|
note: the lint level is defined here
--> $DIR/exhaustive_enums.rs:3:9
|
LL | #![deny(clippy::exhaustive_enums)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: try adding #[non_exhaustive]
|
LL | #[non_exhaustive]
LL | enum Exhaustive {
LL | Foo,
LL | Bar,
LL | Baz,
LL | Quux(String),
...
error: aborting due to previous error