Add exhaustive_structs lint

This commit is contained in:
Manish Goregaokar 2021-01-21 13:41:57 -08:00
parent 09d4d49299
commit 8cb7e85006
6 changed files with 199 additions and 81 deletions

View file

@ -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_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS]);
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, 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,

View file

@ -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),