diff --git a/CHANGELOG.md b/CHANGELOG.md index 39751ef031c2..b446de51c02b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -306,6 +306,7 @@ All notable changes to this project will be documented in this file. [`double_parens`]: https://github.com/Manishearth/rust-clippy/wiki#double_parens [`drop_ref`]: https://github.com/Manishearth/rust-clippy/wiki#drop_ref [`duplicate_underscore_argument`]: https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument +[`empty_enum`]: https://github.com/Manishearth/rust-clippy/wiki#empty_enum [`empty_loop`]: https://github.com/Manishearth/rust-clippy/wiki#empty_loop [`enum_clike_unportable_variant`]: https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant [`enum_glob_use`]: https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use diff --git a/README.md b/README.md index 18166118361e..eb1af46c2346 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ transparently: ## Lints -There are 184 lints included in this crate: +There are 185 lints included in this crate: name | default | triggers on -----------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------- @@ -220,6 +220,7 @@ name [double_parens](https://github.com/Manishearth/rust-clippy/wiki#double_parens) | warn | Warn on unnecessary double parentheses [drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | calls to `std::mem::drop` with a reference instead of an owned value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | function arguments having names which only differ by an underscore +[empty_enum](https://github.com/Manishearth/rust-clippy/wiki#empty_enum) | allow | enum with no variants [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}`, which should block or sleep [enum_clike_unportable_variant](https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant) | warn | C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` [enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | use items that import all variants of an enum diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs new file mode 100644 index 000000000000..631ac8b0fe26 --- /dev/null +++ b/clippy_lints/src/empty_enum.rs @@ -0,0 +1,46 @@ +//! lint when there is an enum with no variants + +use rustc::lint::*; +use rustc::hir::*; +use utils::span_lint_and_then; + +/// **What it does:** Checks for `enum`s with no variants. +/// +/// **Why is this bad?** Enum's with no variants should be replaced with `!`, the uninhabited type, +/// or a wrapper around it. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// enum Test {} +/// ``` +declare_lint! { + pub EMPTY_ENUM, + Allow, + "enum with no variants" +} + +#[derive(Copy,Clone)] +pub struct EmptyEnum; + +impl LintPass for EmptyEnum { + fn get_lints(&self) -> LintArray { + lint_array!(EMPTY_ENUM) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + let did = cx.tcx.hir.local_def_id(item.id); + if let ItemEnum(..) = item.node { + let ty = cx.tcx.item_type(did); + let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); + if adt.variants.is_empty() { + span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| { + db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it"); + }); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bbdd62a3013a..c4f5458b002f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -72,6 +72,7 @@ pub mod derive; pub mod doc; pub mod double_parens; pub mod drop_forget_ref; +pub mod empty_enum; pub mod entry; pub mod enum_clike; pub mod enum_glob_use; @@ -265,6 +266,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { max_single_char_names: conf.max_single_char_names, }); reg.register_late_lint_pass(box drop_forget_ref::Pass); + reg.register_late_lint_pass(box empty_enum::EmptyEnum); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); reg.register_late_lint_pass(box types::InvalidUpcastComparisons); reg.register_late_lint_pass(box regex::Pass::default()); @@ -304,6 +306,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_lint_group("clippy_pedantic", vec![ booleans::NONMINIMAL_BOOL, + empty_enum::EMPTY_ENUM, enum_glob_use::ENUM_GLOB_USE, enum_variants::PUB_ENUM_VARIANT_NAMES, enum_variants::STUTTER, diff --git a/tests/compile-fail/empty_enum.rs b/tests/compile-fail/empty_enum.rs new file mode 100644 index 000000000000..ac9b314c00a6 --- /dev/null +++ b/tests/compile-fail/empty_enum.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(dead_code)] +#![deny(empty_enum)] + +enum Empty {} //~ ERROR enum with no variants + //~^ HELP consider using the uninhabited type `!` or a wrapper around it + +fn main() { +} diff --git a/tests/compile-fail/enum_glob_use.rs b/tests/compile-fail/enum_glob_use.rs index 12fd104312a9..86539c2b13ef 100644 --- a/tests/compile-fail/enum_glob_use.rs +++ b/tests/compile-fail/enum_glob_use.rs @@ -5,7 +5,9 @@ use std::cmp::Ordering::*; //~ ERROR: don't use glob imports for enum variants -enum Enum {} +enum Enum { + _Foo, +} use self::Enum::*; //~ ERROR: don't use glob imports for enum variants