diff --git a/CHANGELOG.md b/CHANGELOG.md
index fef25ad86..26c9877db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5463,6 +5463,7 @@ Released 2018-09-13
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
+[`struct_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names
[`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter
[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
@@ -5625,6 +5626,7 @@ Released 2018-09-13
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack
[`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold
+[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold
[`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold
[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold
[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index 2c958ccbb..2c1ec748a 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -273,6 +273,16 @@ The minimum number of enum variants for the lints about variant names to trigger
* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
+## `struct-field-name-threshold`
+The minimum number of struct fields for the lints about field names to trigger
+
+**Default Value:** `3` (`u64`)
+
+---
+**Affected lints:**
+* [`struct_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_variant_names)
+
+
## `enum-variant-size-threshold`
The maximum size of an enum's variant to avoid box suggestion
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 481c44031..77438b27f 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -154,9 +154,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO,
crate::entry::MAP_ENTRY_INFO,
crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
- crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
- crate::enum_variants::MODULE_INCEPTION_INFO,
- crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
crate::escape::BOXED_LOCAL_INFO,
@@ -226,6 +223,10 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
crate::int_plus_one::INT_PLUS_ONE_INFO,
crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
+ crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
+ crate::item_name_repetitions::MODULE_INCEPTION_INFO,
+ crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO,
+ crate::item_name_repetitions::STRUCT_FIELD_NAMES_INFO,
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs
index 55ebd44a6..716908483 100644
--- a/clippy_lints/src/functions/mod.rs
+++ b/clippy_lints/src/functions/mod.rs
@@ -360,6 +360,7 @@ declare_clippy_lint! {
}
#[derive(Copy, Clone)]
+#[allow(clippy::struct_field_names)]
pub struct Functions {
too_many_arguments_threshold: u64,
too_many_lines_threshold: u64,
diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/item_name_repetitions.rs
similarity index 60%
rename from clippy_lints/src/enum_variants.rs
rename to clippy_lints/src/item_name_repetitions.rs
index e332f681b..8b4984da3 100644
--- a/clippy_lints/src/enum_variants.rs
+++ b/clippy_lints/src/item_name_repetitions.rs
@@ -1,9 +1,10 @@
//! lint on enum variants that are prefixed or suffixed by the same characters
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
+use clippy_utils::macros::span_is_local;
use clippy_utils::source::is_present_in_source;
-use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
-use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant};
+use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
+use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@@ -103,32 +104,184 @@ declare_clippy_lint! {
style,
"modules that have the same name as their parent module"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects struct fields that are prefixed or suffixed
+ /// by the same characters or the name of the struct itself.
+ ///
+ /// ### Why is this bad?
+ /// Information common to all struct fields is better represented in the struct name.
+ ///
+ /// ### Limitations
+ /// Characters with no casing will be considered when comparing prefixes/suffixes
+ /// This applies to numbers and non-ascii characters without casing
+ /// e.g. `foo1` and `foo2` is considered to have different prefixes
+ /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹`
+ ///
+ /// ### Example
+ /// ```rust
+ /// struct Cake {
+ /// cake_sugar: u8,
+ /// cake_flour: u8,
+ /// cake_eggs: u8
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// struct Cake {
+ /// sugar: u8,
+ /// flour: u8,
+ /// eggs: u8
+ /// }
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub STRUCT_FIELD_NAMES,
+ pedantic,
+ "structs where all fields share a prefix/postfix or contain the name of the struct"
+}
-pub struct EnumVariantNames {
+pub struct ItemNameRepetitions {
modules: Vec<(Symbol, String, OwnerId)>,
- threshold: u64,
+ enum_threshold: u64,
+ struct_threshold: u64,
avoid_breaking_exported_api: bool,
allow_private_module_inception: bool,
}
-impl EnumVariantNames {
+impl ItemNameRepetitions {
#[must_use]
- pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self {
+ pub fn new(
+ enum_threshold: u64,
+ struct_threshold: u64,
+ avoid_breaking_exported_api: bool,
+ allow_private_module_inception: bool,
+ ) -> Self {
Self {
modules: Vec::new(),
- threshold,
+ enum_threshold,
+ struct_threshold,
avoid_breaking_exported_api,
allow_private_module_inception,
}
}
}
-impl_lint_pass!(EnumVariantNames => [
+impl_lint_pass!(ItemNameRepetitions => [
ENUM_VARIANT_NAMES,
+ STRUCT_FIELD_NAMES,
MODULE_NAME_REPETITIONS,
MODULE_INCEPTION
]);
+#[must_use]
+fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
+ prefixes.iter().all(|p| p == &"" || p == &"_")
+}
+
+fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+ if (fields.len() as u64) < threshold {
+ return;
+ }
+
+ check_struct_name_repetition(cx, item, fields);
+
+ // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
+ // this prevents linting in macros in which the location of the field identifier names differ
+ if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) {
+ return;
+ }
+
+ let mut pre: Vec<&str> = match fields.first() {
+ Some(first_field) => first_field.ident.name.as_str().split('_').collect(),
+ None => return,
+ };
+ let mut post = pre.clone();
+ post.reverse();
+ for field in fields {
+ let field_split: Vec<&str> = field.ident.name.as_str().split('_').collect();
+ if field_split.len() == 1 {
+ return;
+ }
+
+ pre = pre
+ .into_iter()
+ .zip(field_split.iter())
+ .take_while(|(a, b)| &a == b)
+ .map(|e| e.0)
+ .collect();
+ post = post
+ .into_iter()
+ .zip(field_split.iter().rev())
+ .take_while(|(a, b)| &a == b)
+ .map(|e| e.0)
+ .collect();
+ }
+ let prefix = pre.join("_");
+ post.reverse();
+ let postfix = match post.last() {
+ Some(&"") => post.join("_") + "_",
+ Some(_) | None => post.join("_"),
+ };
+ if fields.len() > 1 {
+ let (what, value) = match (
+ prefix.is_empty() || prefix.chars().all(|c| c == '_'),
+ postfix.is_empty(),
+ ) {
+ (true, true) => return,
+ (false, _) => ("pre", prefix),
+ (true, false) => ("post", postfix),
+ };
+ span_lint_and_help(
+ cx,
+ STRUCT_FIELD_NAMES,
+ item.span,
+ &format!("all fields have the same {what}fix: `{value}`"),
+ None,
+ &format!("remove the {what}fixes"),
+ );
+ }
+}
+
+fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+ let snake_name = to_snake_case(item.ident.name.as_str());
+ let item_name_words: Vec<&str> = snake_name.split('_').collect();
+ for field in fields {
+ if field.ident.span.eq_ctxt(item.ident.span) {
+ //consider linting only if the field identifier has the same SyntaxContext as the item(struct)
+ let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect();
+ if field_words.len() >= item_name_words.len() {
+ // if the field name is shorter than the struct name it cannot contain it
+ if field_words.iter().zip(item_name_words.iter()).all(|(a, b)| a == b) {
+ span_lint_hir(
+ cx,
+ STRUCT_FIELD_NAMES,
+ field.hir_id,
+ field.span,
+ "field name starts with the struct's name",
+ );
+ }
+ if field_words.len() > item_name_words.len() {
+ // lint only if the end is not covered by the start
+ if field_words
+ .iter()
+ .rev()
+ .zip(item_name_words.iter().rev())
+ .all(|(a, b)| a == b)
+ {
+ span_lint_hir(
+ cx,
+ STRUCT_FIELD_NAMES,
+ field.hir_id,
+ field.span,
+ "field name ends with the struct's name",
+ );
+ }
+ }
+ }
+ }
+ }
+}
+
fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
let name = variant.ident.name.as_str();
let item_name_chars = item_name.chars().count();
@@ -218,35 +371,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
);
}
-#[must_use]
-fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
- prefixes.iter().all(|p| p == &"" || p == &"_")
-}
-
-#[must_use]
-fn to_camel_case(item_name: &str) -> String {
- let mut s = String::new();
- let mut up = true;
- for c in item_name.chars() {
- if c.is_uppercase() {
- // we only turn snake case text into CamelCase
- return item_name.to_string();
- }
- if c == '_' {
- up = true;
- continue;
- }
- if up {
- up = false;
- s.extend(c.to_uppercase());
- } else {
- s.push(c);
- }
- }
- s
-}
-
-impl LateLintPass<'_> for EnumVariantNames {
+impl LateLintPass<'_> for ItemNameRepetitions {
fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
let last = self.modules.pop();
assert!(last.is_some());
@@ -303,9 +428,15 @@ impl LateLintPass<'_> for EnumVariantNames {
}
}
}
- if let ItemKind::Enum(ref def, _) = item.kind {
- if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
- check_variant(cx, self.threshold, def, item_name, item.span);
+ if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id))
+ && span_is_local(item.span)
+ {
+ match item.kind {
+ ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
+ ItemKind::Struct(VariantData::Struct(fields, _), _) => {
+ check_fields(cx, self.struct_threshold, item, fields);
+ },
+ _ => (),
}
}
self.modules.push((item.ident.name, item_camel, item.owner_id));
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 2d02ce8b4..7b97adcf2 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -121,7 +121,6 @@ mod empty_structs_with_brackets;
mod endian_bytes;
mod entry;
mod enum_clike;
-mod enum_variants;
mod equatable_if_let;
mod error_impl_error;
mod escape;
@@ -166,6 +165,7 @@ mod inline_fn_without_body;
mod instant_subtraction;
mod int_plus_one;
mod invalid_upcast_comparisons;
+mod item_name_repetitions;
mod items_after_statements;
mod items_after_test_module;
mod iter_not_returning_iterator;
@@ -852,10 +852,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+ let struct_field_name_threshold = conf.struct_field_name_threshold;
let allow_private_module_inception = conf.allow_private_module_inception;
store.register_late_pass(move |_| {
- Box::new(enum_variants::EnumVariantNames::new(
+ Box::new(item_name_repetitions::ItemNameRepetitions::new(
enum_variant_name_threshold,
+ struct_field_name_threshold,
avoid_breaking_exported_api,
allow_private_module_inception,
))
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 3dc652f9d..f0f8d510c 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -134,6 +134,7 @@ impl Usage {
/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
/// `DefId` of the function paired with the parameter's index.
#[derive(Default)]
+#[allow(clippy::struct_field_names)]
struct Params {
params: Vec,
by_id: HirIdMap,
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index 71a4b3fba..788678a63 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -578,7 +578,7 @@ impl Types {
}
}
-#[allow(clippy::struct_excessive_bools)]
+#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)]
#[derive(Clone, Copy, Default)]
struct CheckTyContext {
is_in_trait_impl: bool,
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 23da1de77..519e27b03 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -360,6 +360,10 @@ define_Conf! {
///
/// The minimum number of enum variants for the lints about variant names to trigger
(enum_variant_name_threshold: u64 = 3),
+ /// Lint: STRUCT_VARIANT_NAMES.
+ ///
+ /// The minimum number of struct fields for the lints about field names to trigger
+ (struct_field_name_threshold: u64 = 3),
/// Lint: LARGE_ENUM_VARIANT.
///
/// The maximum size of an enum's variant to avoid box suggestion
diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs
index 03a9d3c25..69c25b427 100644
--- a/clippy_utils/src/str_utils.rs
+++ b/clippy_utils/src/str_utils.rs
@@ -236,6 +236,59 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
})
}
+/// Returns a `snake_case` version of the input
+/// ```
+/// use clippy_utils::str_utils::to_snake_case;
+/// assert_eq!(to_snake_case("AbcDef"), "abc_def");
+/// assert_eq!(to_snake_case("ABCD"), "a_b_c_d");
+/// assert_eq!(to_snake_case("AbcDD"), "abc_d_d");
+/// assert_eq!(to_snake_case("Abc1DD"), "abc1_d_d");
+/// ```
+pub fn to_snake_case(name: &str) -> String {
+ let mut s = String::new();
+ for (i, c) in name.chars().enumerate() {
+ if c.is_uppercase() {
+ // characters without capitalization are considered lowercase
+ if i != 0 {
+ s.push('_');
+ }
+ s.extend(c.to_lowercase());
+ } else {
+ s.push(c);
+ }
+ }
+ s
+}
+/// Returns a `CamelCase` version of the input
+/// ```
+/// use clippy_utils::str_utils::to_camel_case;
+/// assert_eq!(to_camel_case("abc_def"), "AbcDef");
+/// assert_eq!(to_camel_case("a_b_c_d"), "ABCD");
+/// assert_eq!(to_camel_case("abc_d_d"), "AbcDD");
+/// assert_eq!(to_camel_case("abc1_d_d"), "Abc1DD");
+/// ```
+pub fn to_camel_case(item_name: &str) -> String {
+ let mut s = String::new();
+ let mut up = true;
+ for c in item_name.chars() {
+ if c.is_uppercase() {
+ // we only turn snake case text into CamelCase
+ return item_name.to_string();
+ }
+ if c == '_' {
+ up = true;
+ continue;
+ }
+ if up {
+ up = false;
+ s.extend(c.to_uppercase());
+ } else {
+ s.push(c);
+ }
+ }
+ s
+}
+
#[cfg(test)]
mod test {
use super::*;
diff --git a/tests/ui-toml/enum_variant_names/enum_variant_names.rs b/tests/ui-toml/enum_variant_names/enum_variant_names.rs
deleted file mode 100644
index 8f4e178cc..000000000
--- a/tests/ui-toml/enum_variant_names/enum_variant_names.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-enum Foo {
- AFoo,
- BFoo,
- CFoo,
- DFoo,
-}
-enum Foo2 {
- //~^ ERROR: all variants have the same postfix
- AFoo,
- BFoo,
- CFoo,
- DFoo,
- EFoo,
-}
-
-fn main() {}
diff --git a/tests/ui-toml/enum_variant_names/enum_variant_names.stderr b/tests/ui-toml/enum_variant_names/enum_variant_names.stderr
deleted file mode 100644
index 11039b1db..000000000
--- a/tests/ui-toml/enum_variant_names/enum_variant_names.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: all variants have the same postfix: `Foo`
- --> $DIR/enum_variant_names.rs:7:1
- |
-LL | / enum Foo2 {
-LL | |
-LL | | AFoo,
-LL | | BFoo,
-... |
-LL | | EFoo,
-LL | | }
- | |_^
- |
- = help: remove the postfixes and use full paths to the variants instead of glob imports
- = note: `-D clippy::enum-variant-names` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]`
-
-error: aborting due to previous error
-
diff --git a/tests/ui-toml/enum_variants_threshold0/clippy.toml b/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
similarity index 50%
rename from tests/ui-toml/enum_variants_threshold0/clippy.toml
rename to tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
index f85aade6a..d41edbaf7 100644
--- a/tests/ui-toml/enum_variants_threshold0/clippy.toml
+++ b/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
@@ -1 +1,2 @@
+struct-field-name-threshold = 0
enum-variant-name-threshold = 0
diff --git a/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs b/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
similarity index 65%
rename from tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs
rename to tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
index 6918d7528..b633dcbd1 100644
--- a/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs
+++ b/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
@@ -1,3 +1,5 @@
+struct Data {}
+
enum Actions {}
fn main() {}
diff --git a/tests/ui-toml/enum_variant_names/clippy.toml b/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
similarity index 50%
rename from tests/ui-toml/enum_variant_names/clippy.toml
rename to tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
index 0ad7a9799..028a62790 100644
--- a/tests/ui-toml/enum_variant_names/clippy.toml
+++ b/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
@@ -1 +1,2 @@
enum-variant-name-threshold = 5
+struct-field-name-threshold = 5
diff --git a/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs
new file mode 100644
index 000000000..d43731169
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs
@@ -0,0 +1,32 @@
+#![warn(clippy::struct_field_names)]
+
+struct Data {
+ a_data: u8,
+ b_data: u8,
+ c_data: u8,
+ d_data: u8,
+}
+struct Data2 {
+ //~^ ERROR: all fields have the same postfix
+ a_data: u8,
+ b_data: u8,
+ c_data: u8,
+ d_data: u8,
+ e_data: u8,
+}
+enum Foo {
+ AFoo,
+ BFoo,
+ CFoo,
+ DFoo,
+}
+enum Foo2 {
+ //~^ ERROR: all variants have the same postfix
+ AFoo,
+ BFoo,
+ CFoo,
+ DFoo,
+ EFoo,
+}
+
+fn main() {}
diff --git a/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr
new file mode 100644
index 000000000..33802c44b
--- /dev/null
+++ b/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr
@@ -0,0 +1,34 @@
+error: all fields have the same postfix: `data`
+ --> $DIR/item_name_repetitions.rs:9:1
+ |
+LL | / struct Data2 {
+LL | |
+LL | | a_data: u8,
+LL | | b_data: u8,
+... |
+LL | | e_data: u8,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes
+ = note: `-D clippy::struct-field-names` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]`
+
+error: all variants have the same postfix: `Foo`
+ --> $DIR/item_name_repetitions.rs:23:1
+ |
+LL | / enum Foo2 {
+LL | |
+LL | | AFoo,
+LL | | BFoo,
+... |
+LL | | EFoo,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes and use full paths to the variants instead of glob imports
+ = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
index 830d71f61..cd53f5044 100644
--- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
+++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
@@ -1,5 +1,6 @@
//! this is crate
#![allow(missing_docs)]
+#![allow(clippy::struct_field_names)]
#![warn(clippy::missing_docs_in_private_items)]
/// this is mod
diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
index 1ecdabbc0..2cf20b460 100644
--- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
+++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
@@ -1,5 +1,5 @@
error: missing documentation for a function
- --> $DIR/pub_crate_missing_doc.rs:12:5
+ --> $DIR/pub_crate_missing_doc.rs:13:5
|
LL | pub(crate) fn crate_no_docs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,25 +8,25 @@ LL | pub(crate) fn crate_no_docs() {}
= help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
error: missing documentation for a function
- --> $DIR/pub_crate_missing_doc.rs:15:5
+ --> $DIR/pub_crate_missing_doc.rs:16:5
|
LL | pub(super) fn super_no_docs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/pub_crate_missing_doc.rs:23:9
+ --> $DIR/pub_crate_missing_doc.rs:24:9
|
LL | pub(crate) fn sub_crate_no_docs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/pub_crate_missing_doc.rs:33:9
+ --> $DIR/pub_crate_missing_doc.rs:34:9
|
LL | pub(crate) crate_field_no_docs: (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct
- --> $DIR/pub_crate_missing_doc.rs:39:5
+ --> $DIR/pub_crate_missing_doc.rs:40:5
|
LL | / pub(crate) struct CrateStructNoDocs {
LL | | /// some docs
@@ -38,13 +38,13 @@ LL | | }
| |_____^
error: missing documentation for a struct field
- --> $DIR/pub_crate_missing_doc.rs:42:9
+ --> $DIR/pub_crate_missing_doc.rs:43:9
|
LL | pub(crate) crate_field_no_docs: (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a type alias
- --> $DIR/pub_crate_missing_doc.rs:51:1
+ --> $DIR/pub_crate_missing_doc.rs:52:1
|
LL | type CrateTypedefNoDocs = String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 4bed5c149..2f9eaa517 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -53,6 +53,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
single-char-binding-names-threshold
stack-size-threshold
standard-macro-braces
+ struct-field-name-threshold
suppress-restriction-lint-in-const
third-party
too-large-for-stack
@@ -126,6 +127,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
single-char-binding-names-threshold
stack-size-threshold
standard-macro-braces
+ struct-field-name-threshold
suppress-restriction-lint-in-const
third-party
too-large-for-stack
diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed
index 4de45e39b..a44c46c14 100644
--- a/tests/ui/manual_filter_map.fixed
+++ b/tests/ui/manual_filter_map.fixed
@@ -2,6 +2,7 @@
#![warn(clippy::manual_filter_map)]
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
#![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
fn main() {
// is_some(), unwrap()
diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs
index 22f316f90..e72d0c430 100644
--- a/tests/ui/manual_filter_map.rs
+++ b/tests/ui/manual_filter_map.rs
@@ -2,6 +2,7 @@
#![warn(clippy::manual_filter_map)]
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
#![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
fn main() {
// is_some(), unwrap()
diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr
index 0bfc1f5c7..cf64bb259 100644
--- a/tests/ui/manual_filter_map.stderr
+++ b/tests/ui/manual_filter_map.stderr
@@ -1,11 +1,11 @@
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:8:19
+ --> $DIR/manual_filter_map.rs:9:19
|
LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:8:30
+ --> $DIR/manual_filter_map.rs:9:30
|
LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^
@@ -13,31 +13,31 @@ LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap
= help: to override `-D warnings` add `#[allow(clippy::manual_filter_map)]`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:11:19
+ --> $DIR/manual_filter_map.rs:12:19
|
LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:11:31
+ --> $DIR/manual_filter_map.rs:12:31
|
LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:14:19
+ --> $DIR/manual_filter_map.rs:15:19
|
LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:14:31
+ --> $DIR/manual_filter_map.rs:15:31
|
LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:17:10
+ --> $DIR/manual_filter_map.rs:18:10
|
LL | .filter(|&x| to_ref(to_opt(x)).is_some())
| __________^
@@ -45,13 +45,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:17:22
+ --> $DIR/manual_filter_map.rs:18:22
|
LL | .filter(|&x| to_ref(to_opt(x)).is_some())
| ^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:20:10
+ --> $DIR/manual_filter_map.rs:21:10
|
LL | .filter(|x| to_ref(to_opt(*x)).is_some())
| __________^
@@ -59,13 +59,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:20:21
+ --> $DIR/manual_filter_map.rs:21:21
|
LL | .filter(|x| to_ref(to_opt(*x)).is_some())
| ^^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:24:10
+ --> $DIR/manual_filter_map.rs:25:10
|
LL | .filter(|&x| to_ref(to_res(x)).is_ok())
| __________^
@@ -73,13 +73,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:24:22
+ --> $DIR/manual_filter_map.rs:25:22
|
LL | .filter(|&x| to_ref(to_res(x)).is_ok())
| ^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:27:10
+ --> $DIR/manual_filter_map.rs:28:10
|
LL | .filter(|x| to_ref(to_res(*x)).is_ok())
| __________^
@@ -87,13 +87,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:27:21
+ --> $DIR/manual_filter_map.rs:28:21
|
LL | .filter(|x| to_ref(to_res(*x)).is_ok())
| ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:33:27
+ --> $DIR/manual_filter_map.rs:34:27
|
LL | iter::