diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1e081e8..49a44d988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3636,6 +3636,7 @@ Released 2018-09-13 [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash +[`unit_like_struct_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_like_struct_brackets [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1fb3ca1fd..f488aab46 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -301,6 +301,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), LintId::of(unit_hash::UNIT_HASH), + LintId::of(unit_like_struct_brackets::UNIT_LIKE_STRUCT_BRACKETS), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_ARG), LintId::of(unit_types::UNIT_CMP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e31617951..a1e6ca76a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -512,6 +512,7 @@ store.register_lints(&[ unicode::UNICODE_NOT_NFC, uninit_vec::UNINIT_VEC, unit_hash::UNIT_HASH, + unit_like_struct_brackets::UNIT_LIKE_STRUCT_BRACKETS, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index dcf399cf9..89657cfb7 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -105,6 +105,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(unit_like_struct_brackets::UNIT_LIKE_STRUCT_BRACKETS), LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(unused_unit::UNUSED_UNIT), LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c8b57956b..af8d9b365 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -380,6 +380,7 @@ mod undropped_manually_drops; mod unicode; mod uninit_vec; mod unit_hash; +mod unit_like_struct_brackets; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -869,6 +870,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }) }); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); + store.register_early_pass(|| Box::new(unit_like_struct_brackets::UnitLikeStructBrackets)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unit_like_struct_brackets.rs b/clippy_lints/src/unit_like_struct_brackets.rs new file mode 100644 index 000000000..0eeb765be --- /dev/null +++ b/clippy_lints/src/unit_like_struct_brackets.rs @@ -0,0 +1,53 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::*; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Finds structs without fields ("unit-like structs") that are declared with brackets. + /// + /// ### Why is this bad? + /// Empty brackets after a struct declaration can be omitted. + /// + /// ### Example + /// ```rust + /// struct Cookie {} + /// ``` + /// Use instead: + /// ```rust + /// struct Cookie; + /// ``` + #[clippy::version = "1.61.0"] + pub UNIT_LIKE_STRUCT_BRACKETS, + style, + "finds struct declarations with empty brackets" +} +declare_lint_pass!(UnitLikeStructBrackets => [UNIT_LIKE_STRUCT_BRACKETS]); + +impl EarlyLintPass for UnitLikeStructBrackets { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if let ItemKind::Struct(var_data, _) = &item.kind && has_no_fields(var_data) { + let span_after_ident = item.span.with_lo(item.ident.span.hi()); + + span_lint_and_sugg( + cx, + UNIT_LIKE_STRUCT_BRACKETS, + span_after_ident, + "found empty brackets on struct declaration", + "remove the brackets", + ";".to_string(), + Applicability::MachineApplicable + ); + } + } +} + +fn has_no_fields(var_data: &VariantData) -> bool { + match var_data { + VariantData::Struct(defs, _) => defs.is_empty(), + VariantData::Tuple(defs, _) => defs.is_empty(), + VariantData::Unit(_) => false, + } +} diff --git a/tests/ui/unit_like_struct_brackets.fixed b/tests/ui/unit_like_struct_brackets.fixed new file mode 100644 index 000000000..a69c310e9 --- /dev/null +++ b/tests/ui/unit_like_struct_brackets.fixed @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::unit_like_struct_brackets)] +#![allow(dead_code)] + +pub struct MyEmptyStruct; // should trigger lint +struct MyEmptyTupleStruct; // should trigger lint + +struct MyStruct { // should not trigger lint + field: u8, +} +struct MyTupleStruct(usize, String); // should not trigger lint + +fn main() {} diff --git a/tests/ui/unit_like_struct_brackets.rs b/tests/ui/unit_like_struct_brackets.rs new file mode 100644 index 000000000..8697a24f1 --- /dev/null +++ b/tests/ui/unit_like_struct_brackets.rs @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::unit_like_struct_brackets)] +#![allow(dead_code)] + +pub struct MyEmptyStruct {} // should trigger lint +struct MyEmptyTupleStruct(); // should trigger lint + +struct MyStruct { // should not trigger lint + field: u8, +} +struct MyTupleStruct(usize, String); // should not trigger lint + +fn main() {} diff --git a/tests/ui/unit_like_struct_brackets.stderr b/tests/ui/unit_like_struct_brackets.stderr new file mode 100644 index 000000000..146ede19c --- /dev/null +++ b/tests/ui/unit_like_struct_brackets.stderr @@ -0,0 +1,16 @@ +error: found empty brackets on struct declaration + --> $DIR/unit_like_struct_brackets.rs:5:25 + | +LL | pub struct MyEmptyStruct {} // should trigger lint + | ^^^ help: remove the brackets: `;` + | + = note: `-D clippy::unit-like-struct-brackets` implied by `-D warnings` + +error: found empty brackets on struct declaration + --> $DIR/unit_like_struct_brackets.rs:6:26 + | +LL | struct MyEmptyTupleStruct(); // should trigger lint + | ^^^ help: remove the brackets: `;` + +error: aborting due to 2 previous errors +