2023-07-03 17:42:48 +00:00
|
|
|
use clippy_utils::diagnostics::span_lint_and_then;
|
|
|
|
use clippy_utils::source::snippet_opt;
|
2023-12-29 19:23:31 +05:30
|
|
|
use rustc_ast::ast::{Item, ItemKind, Variant, VariantData};
|
2022-04-07 18:39:59 +01:00
|
|
|
use rustc_errors::Applicability;
|
|
|
|
use rustc_lexer::TokenKind;
|
|
|
|
use rustc_lint::{EarlyContext, EarlyLintPass};
|
2023-11-25 17:45:27 +00:00
|
|
|
use rustc_session::declare_lint_pass;
|
2022-04-07 18:39:59 +01:00
|
|
|
use rustc_span::Span;
|
|
|
|
|
|
|
|
declare_clippy_lint! {
|
|
|
|
/// ### What it does
|
|
|
|
/// Finds structs without fields (a so-called "empty struct") that are declared with brackets.
|
|
|
|
///
|
For restriction lints, replace “Why is this bad?” with “Why restrict this?”
The `restriction` group contains many lints which are not about
necessarily “bad” things, but style choices — perhaps even style choices
which contradict conventional Rust style — or are otherwise very
situational. This results in silly wording like “Why is this bad?
It isn't, but ...”, which I’ve seen confuse a newcomer at least once.
To improve this situation, this commit replaces the “Why is this bad?”
section heading with “Why restrict this?”, for most, but not all,
restriction lints. I left alone the ones whose placement in the
restriction group is more incidental.
In order to make this make sense, I had to remove the “It isn't, but”
texts from the contents of the sections. Sometimes further changes
were needed, or there were obvious fixes to make, and I went ahead
and made those changes without attempting to split them into another
commit, even though many of them are not strictly necessary for the
“Why restrict this?” project.
2024-05-22 22:21:01 -07:00
|
|
|
/// ### Why restrict this?
|
|
|
|
/// Empty brackets after a struct declaration can be omitted,
|
|
|
|
/// and it may be desirable to do so consistently for style.
|
|
|
|
///
|
|
|
|
/// However, removing the brackets also introduces a public constant named after the struct,
|
|
|
|
/// so this is not just a syntactic simplification but an an API change, and adding them back
|
|
|
|
/// is a *breaking* API change.
|
2022-04-07 18:39:59 +01:00
|
|
|
///
|
|
|
|
/// ### Example
|
2023-10-23 13:49:18 +00:00
|
|
|
/// ```no_run
|
2022-04-07 18:39:59 +01:00
|
|
|
/// struct Cookie {}
|
For restriction lints, replace “Why is this bad?” with “Why restrict this?”
The `restriction` group contains many lints which are not about
necessarily “bad” things, but style choices — perhaps even style choices
which contradict conventional Rust style — or are otherwise very
situational. This results in silly wording like “Why is this bad?
It isn't, but ...”, which I’ve seen confuse a newcomer at least once.
To improve this situation, this commit replaces the “Why is this bad?”
section heading with “Why restrict this?”, for most, but not all,
restriction lints. I left alone the ones whose placement in the
restriction group is more incidental.
In order to make this make sense, I had to remove the “It isn't, but”
texts from the contents of the sections. Sometimes further changes
were needed, or there were obvious fixes to make, and I went ahead
and made those changes without attempting to split them into another
commit, even though many of them are not strictly necessary for the
“Why restrict this?” project.
2024-05-22 22:21:01 -07:00
|
|
|
/// struct Biscuit();
|
2022-04-07 18:39:59 +01:00
|
|
|
/// ```
|
|
|
|
/// Use instead:
|
2023-10-23 13:49:18 +00:00
|
|
|
/// ```no_run
|
2022-04-07 18:39:59 +01:00
|
|
|
/// struct Cookie;
|
For restriction lints, replace “Why is this bad?” with “Why restrict this?”
The `restriction` group contains many lints which are not about
necessarily “bad” things, but style choices — perhaps even style choices
which contradict conventional Rust style — or are otherwise very
situational. This results in silly wording like “Why is this bad?
It isn't, but ...”, which I’ve seen confuse a newcomer at least once.
To improve this situation, this commit replaces the “Why is this bad?”
section heading with “Why restrict this?”, for most, but not all,
restriction lints. I left alone the ones whose placement in the
restriction group is more incidental.
In order to make this make sense, I had to remove the “It isn't, but”
texts from the contents of the sections. Sometimes further changes
were needed, or there were obvious fixes to make, and I went ahead
and made those changes without attempting to split them into another
commit, even though many of them are not strictly necessary for the
“Why restrict this?” project.
2024-05-22 22:21:01 -07:00
|
|
|
/// struct Biscuit;
|
2022-04-07 18:39:59 +01:00
|
|
|
/// ```
|
|
|
|
#[clippy::version = "1.62.0"]
|
|
|
|
pub EMPTY_STRUCTS_WITH_BRACKETS,
|
|
|
|
restriction,
|
|
|
|
"finds struct declarations with empty brackets"
|
|
|
|
}
|
|
|
|
|
2023-12-29 19:23:31 +05:30
|
|
|
declare_clippy_lint! {
|
|
|
|
/// ### What it does
|
|
|
|
/// Finds enum variants without fields that are declared with empty brackets.
|
|
|
|
///
|
For restriction lints, replace “Why is this bad?” with “Why restrict this?”
The `restriction` group contains many lints which are not about
necessarily “bad” things, but style choices — perhaps even style choices
which contradict conventional Rust style — or are otherwise very
situational. This results in silly wording like “Why is this bad?
It isn't, but ...”, which I’ve seen confuse a newcomer at least once.
To improve this situation, this commit replaces the “Why is this bad?”
section heading with “Why restrict this?”, for most, but not all,
restriction lints. I left alone the ones whose placement in the
restriction group is more incidental.
In order to make this make sense, I had to remove the “It isn't, but”
texts from the contents of the sections. Sometimes further changes
were needed, or there were obvious fixes to make, and I went ahead
and made those changes without attempting to split them into another
commit, even though many of them are not strictly necessary for the
“Why restrict this?” project.
2024-05-22 22:21:01 -07:00
|
|
|
/// ### Why restrict this?
|
|
|
|
/// Empty brackets after a enum variant declaration are redundant and can be omitted,
|
|
|
|
/// and it may be desirable to do so consistently for style.
|
|
|
|
///
|
|
|
|
/// However, removing the brackets also introduces a public constant named after the variant,
|
|
|
|
/// so this is not just a syntactic simplification but an an API change, and adding them back
|
|
|
|
/// is a *breaking* API change.
|
2023-12-29 19:23:31 +05:30
|
|
|
///
|
|
|
|
/// ### Example
|
|
|
|
/// ```no_run
|
|
|
|
/// enum MyEnum {
|
|
|
|
/// HasData(u8),
|
For restriction lints, replace “Why is this bad?” with “Why restrict this?”
The `restriction` group contains many lints which are not about
necessarily “bad” things, but style choices — perhaps even style choices
which contradict conventional Rust style — or are otherwise very
situational. This results in silly wording like “Why is this bad?
It isn't, but ...”, which I’ve seen confuse a newcomer at least once.
To improve this situation, this commit replaces the “Why is this bad?”
section heading with “Why restrict this?”, for most, but not all,
restriction lints. I left alone the ones whose placement in the
restriction group is more incidental.
In order to make this make sense, I had to remove the “It isn't, but”
texts from the contents of the sections. Sometimes further changes
were needed, or there were obvious fixes to make, and I went ahead
and made those changes without attempting to split them into another
commit, even though many of them are not strictly necessary for the
“Why restrict this?” project.
2024-05-22 22:21:01 -07:00
|
|
|
/// HasNoData(), // redundant parentheses
|
|
|
|
/// NoneHereEither {}, // redundant braces
|
2023-12-29 19:23:31 +05:30
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Use instead:
|
|
|
|
/// ```no_run
|
|
|
|
/// enum MyEnum {
|
|
|
|
/// HasData(u8),
|
|
|
|
/// HasNoData,
|
For restriction lints, replace “Why is this bad?” with “Why restrict this?”
The `restriction` group contains many lints which are not about
necessarily “bad” things, but style choices — perhaps even style choices
which contradict conventional Rust style — or are otherwise very
situational. This results in silly wording like “Why is this bad?
It isn't, but ...”, which I’ve seen confuse a newcomer at least once.
To improve this situation, this commit replaces the “Why is this bad?”
section heading with “Why restrict this?”, for most, but not all,
restriction lints. I left alone the ones whose placement in the
restriction group is more incidental.
In order to make this make sense, I had to remove the “It isn't, but”
texts from the contents of the sections. Sometimes further changes
were needed, or there were obvious fixes to make, and I went ahead
and made those changes without attempting to split them into another
commit, even though many of them are not strictly necessary for the
“Why restrict this?” project.
2024-05-22 22:21:01 -07:00
|
|
|
/// NoneHereEither,
|
2023-12-29 19:23:31 +05:30
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[clippy::version = "1.77.0"]
|
|
|
|
pub EMPTY_ENUM_VARIANTS_WITH_BRACKETS,
|
|
|
|
restriction,
|
|
|
|
"finds enum variants with empty brackets"
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]);
|
|
|
|
|
|
|
|
impl EarlyLintPass for EmptyWithBrackets {
|
2022-04-07 18:39:59 +01:00
|
|
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
|
|
|
let span_after_ident = item.span.with_lo(item.ident.span.hi());
|
|
|
|
|
|
|
|
if let ItemKind::Struct(var_data, _) = &item.kind
|
|
|
|
&& has_brackets(var_data)
|
2023-11-02 17:12:25 +01:00
|
|
|
&& has_no_fields(cx, var_data, span_after_ident)
|
|
|
|
{
|
2022-04-07 18:39:59 +01:00
|
|
|
span_lint_and_then(
|
|
|
|
cx,
|
|
|
|
EMPTY_STRUCTS_WITH_BRACKETS,
|
|
|
|
span_after_ident,
|
|
|
|
"found empty brackets on struct declaration",
|
|
|
|
|diagnostic| {
|
|
|
|
diagnostic.span_suggestion_hidden(
|
|
|
|
span_after_ident,
|
|
|
|
"remove the brackets",
|
2022-06-13 15:48:40 +09:00
|
|
|
";",
|
2023-11-02 17:12:25 +01:00
|
|
|
Applicability::Unspecified,
|
|
|
|
);
|
|
|
|
},
|
2022-04-07 18:39:59 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2023-12-29 19:23:31 +05:30
|
|
|
|
|
|
|
fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &Variant) {
|
|
|
|
let span_after_ident = variant.span.with_lo(variant.ident.span.hi());
|
|
|
|
|
|
|
|
if has_brackets(&variant.data) && has_no_fields(cx, &variant.data, span_after_ident) {
|
|
|
|
span_lint_and_then(
|
|
|
|
cx,
|
|
|
|
EMPTY_ENUM_VARIANTS_WITH_BRACKETS,
|
|
|
|
span_after_ident,
|
|
|
|
"enum variant has empty brackets",
|
|
|
|
|diagnostic| {
|
|
|
|
diagnostic.span_suggestion_hidden(
|
|
|
|
span_after_ident,
|
|
|
|
"remove the brackets",
|
|
|
|
"",
|
2023-12-30 22:22:44 +05:30
|
|
|
Applicability::MaybeIncorrect,
|
2023-12-29 19:23:31 +05:30
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2022-04-07 18:39:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn has_no_ident_token(braces_span_str: &str) -> bool {
|
|
|
|
!rustc_lexer::tokenize(braces_span_str).any(|t| t.kind == TokenKind::Ident)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn has_brackets(var_data: &VariantData) -> bool {
|
|
|
|
!matches!(var_data, VariantData::Unit(_))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Span) -> bool {
|
|
|
|
if !var_data.fields().is_empty() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// there might still be field declarations hidden from the AST
|
2022-05-05 15:12:52 +01:00
|
|
|
// (conditionally compiled code using #[cfg(..)])
|
2022-04-07 18:39:59 +01:00
|
|
|
|
|
|
|
let Some(braces_span_str) = snippet_opt(cx, braces_span) else {
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
has_no_ident_token(braces_span_str.as_ref())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod unit_test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_has_no_ident_token() {
|
|
|
|
let input = "{ field: u8 }";
|
|
|
|
assert!(!has_no_ident_token(input));
|
|
|
|
|
|
|
|
let input = "(u8, String);";
|
|
|
|
assert!(!has_no_ident_token(input));
|
|
|
|
|
|
|
|
let input = " {
|
|
|
|
// test = 5
|
|
|
|
}
|
|
|
|
";
|
|
|
|
assert!(has_no_ident_token(input));
|
|
|
|
|
|
|
|
let input = " ();";
|
|
|
|
assert!(has_no_ident_token(input));
|
|
|
|
}
|
|
|
|
}
|