about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjonboh <jon.bosque.hernando@gmail.com>2023-10-17 18:34:27 +0200
committerjonboh <jon.bosque.hernando@gmail.com>2023-10-18 19:20:08 +0200
commit8b02dac54244efc2968c164bff129f2a64bb845e (patch)
treea28b8da1d459c6c3a9c86317dfaab5d2189dc2b4
parent2640d5cc85ff32de901d36cebbd48ccf0b398453 (diff)
downloadrust-8b02dac54244efc2968c164bff129f2a64bb845e.tar.gz
rust-8b02dac54244efc2968c164bff129f2a64bb845e.zip
add lint for struct field names
side effect for `enum_variants`:
use .first() instead of .get(0) in enum_variants lint
move to_camel_case to str_util module
move module, enum and struct name repetitions check to a single file `item_name_repetitions`
rename enum_variants threshold config option
-rw-r--r--CHANGELOG.md2
-rw-r--r--book/src/lint_configuration.md10
-rw-r--r--clippy_lints/src/declared_lints.rs7
-rw-r--r--clippy_lints/src/functions/mod.rs1
-rw-r--r--clippy_lints/src/item_name_repetitions.rs (renamed from clippy_lints/src/enum_variants.rs)211
-rw-r--r--clippy_lints/src/lib.rs6
-rw-r--r--clippy_lints/src/only_used_in_recursion.rs1
-rw-r--r--clippy_lints/src/types/mod.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs4
-rw-r--r--clippy_utils/src/str_utils.rs53
-rw-r--r--tests/ui-toml/enum_variant_names/enum_variant_names.rs16
-rw-r--r--tests/ui-toml/enum_variant_names/enum_variant_names.stderr18
-rw-r--r--tests/ui-toml/item_name_repetitions/threshold0/clippy.toml (renamed from tests/ui-toml/enum_variants_threshold0/clippy.toml)1
-rw-r--r--tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs (renamed from tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs)2
-rw-r--r--tests/ui-toml/item_name_repetitions/threshold5/clippy.toml (renamed from tests/ui-toml/enum_variant_names/clippy.toml)1
-rw-r--r--tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs32
-rw-r--r--tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr34
-rw-r--r--tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs1
-rw-r--r--tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr14
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--tests/ui/manual_filter_map.fixed1
-rw-r--r--tests/ui/manual_filter_map.rs1
-rw-r--r--tests/ui/manual_filter_map.stderr76
-rw-r--r--tests/ui/manual_find_map.fixed1
-rw-r--r--tests/ui/manual_find_map.rs1
-rw-r--r--tests/ui/manual_find_map.stderr78
-rw-r--r--tests/ui/min_ident_chars.rs1
-rw-r--r--tests/ui/min_ident_chars.stderr58
-rw-r--r--tests/ui/misnamed_getters.fixed1
-rw-r--r--tests/ui/misnamed_getters.rs1
-rw-r--r--tests/ui/misnamed_getters.stderr36
-rw-r--r--tests/ui/needless_bool/fixable.fixed3
-rw-r--r--tests/ui/needless_bool/fixable.rs3
-rw-r--r--tests/ui/needless_bool/fixable.stderr42
-rw-r--r--tests/ui/rest_pat_in_fully_bound_structs.rs1
-rw-r--r--tests/ui/rest_pat_in_fully_bound_structs.stderr6
-rw-r--r--tests/ui/struct_fields.rs331
-rw-r--r--tests/ui/struct_fields.stderr265
38 files changed, 1087 insertions, 237 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fef25ad8635..26c9877dbff 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 2c958ccbbc2..2c1ec748a4e 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 481c44031cf..77438b27f90 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 55ebd44a60c..716908483e9 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
index e332f681b6d..8b4984da3dd 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 2d02ce8b4f0..7b97adcf226 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 3dc652f9dc0..f0f8d510c7e 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<Param>,
     by_id: HirIdMap<usize>,
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index 71a4b3fba1b..788678a63b7 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 23da1de7730..519e27b0367 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 03a9d3c25fd..69c25b427e1 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 8f4e178ccfe..00000000000
--- 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 11039b1db48..00000000000
--- 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
index f85aade6ae8..d41edbaf7fa 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
index 6918d7528c1..b633dcbd19e 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
index 0ad7a979948..028a6279079 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 00000000000..d437311691d
--- /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 00000000000..33802c44bf9
--- /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 830d71f61dd..cd53f504459 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 1ecdabbc03e..2cf20b46049 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 4bed5c149f5..2f9eaa5178c 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 4de45e39b10..a44c46c145c 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 22f316f90b6..e72d0c4305b 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 0bfc1f5c745..cf64bb25951 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::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
@@ -102,79 +102,79 @@ LL |     iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()
    = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:34:28
+  --> $DIR/manual_filter_map.rs:35:28
    |
 LL |     iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:35:31
+  --> $DIR/manual_filter_map.rs:36:31
    |
 LL |     iter::<&Option<String>>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:36:31
+  --> $DIR/manual_filter_map.rs:37:31
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
    |
 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:36:41
+  --> $DIR/manual_filter_map.rs:37:41
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:38:30
+  --> $DIR/manual_filter_map.rs:39:30
    |
 LL |     iter::<Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:39:31
+  --> $DIR/manual_filter_map.rs:40:31
    |
 LL |     iter::<&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:40:32
+  --> $DIR/manual_filter_map.rs:41:32
    |
 LL |     iter::<&&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:41:31
+  --> $DIR/manual_filter_map.rs:42:31
    |
 LL |     iter::<Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:42:32
+  --> $DIR/manual_filter_map.rs:43:32
    |
 LL |     iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:43:35
+  --> $DIR/manual_filter_map.rs:44:35
    |
 LL |     iter::<&Result<String, ()>>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:44:35
+  --> $DIR/manual_filter_map.rs:45:35
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().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:44:45
+  --> $DIR/manual_filter_map.rs:45:45
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                             ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:92:10
+  --> $DIR/manual_filter_map.rs:93:10
    |
 LL |           .filter(|f| f.option_field.is_some())
    |  __________^
@@ -182,7 +182,7 @@ LL | |         .map(|f| f.option_field.clone().unwrap());
    | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:97:10
+  --> $DIR/manual_filter_map.rs:98:10
    |
 LL |           .filter(|f| f.ref_field.is_some())
    |  __________^
@@ -190,7 +190,7 @@ LL | |         .map(|f| f.ref_field.cloned().unwrap());
    | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:102:10
+  --> $DIR/manual_filter_map.rs:103:10
    |
 LL |           .filter(|f| f.ref_field.is_some())
    |  __________^
@@ -198,7 +198,7 @@ LL | |         .map(|f| f.ref_field.copied().unwrap());
    | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:107:10
+  --> $DIR/manual_filter_map.rs:108:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -206,7 +206,7 @@ LL | |         .map(|f| f.result_field.clone().unwrap());
    | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:112:10
+  --> $DIR/manual_filter_map.rs:113:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -214,7 +214,7 @@ LL | |         .map(|f| f.result_field.as_ref().unwrap());
    | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:117:10
+  --> $DIR/manual_filter_map.rs:118:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -222,7 +222,7 @@ LL | |         .map(|f| f.result_field.as_deref().unwrap());
    | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:122:10
+  --> $DIR/manual_filter_map.rs:123:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -230,7 +230,7 @@ LL | |         .map(|f| f.result_field.as_mut().unwrap());
    | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:127:10
+  --> $DIR/manual_filter_map.rs:128:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -238,7 +238,7 @@ LL | |         .map(|f| f.result_field.as_deref_mut().unwrap());
    | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:132:10
+  --> $DIR/manual_filter_map.rs:133:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -246,7 +246,7 @@ LL | |         .map(|f| f.result_field.to_owned().unwrap());
    | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:145:27
+  --> $DIR/manual_filter_map.rs:146:27
    |
 LL |       let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
    |  ___________________________^
@@ -256,7 +256,7 @@ LL | |     });
    | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:155:10
+  --> $DIR/manual_filter_map.rs:156:10
    |
 LL |           .filter(|x| matches!(x, Enum::A(_)))
    |  __________^
diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed
index 0e92d25e68f..2d9a356b9bc 100644
--- a/tests/ui/manual_find_map.fixed
+++ b/tests/ui/manual_find_map.fixed
@@ -2,6 +2,7 @@
 #![warn(clippy::manual_find_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_find_map.rs b/tests/ui/manual_find_map.rs
index b2568c823eb..7c5cc136695 100644
--- a/tests/ui/manual_find_map.rs
+++ b/tests/ui/manual_find_map.rs
@@ -2,6 +2,7 @@
 #![warn(clippy::manual_find_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_find_map.stderr b/tests/ui/manual_find_map.stderr
index 0dc9ae1df03..0526382323d 100644
--- a/tests/ui/manual_find_map.stderr
+++ b/tests/ui/manual_find_map.stderr
@@ -1,11 +1,11 @@
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:8:19
+  --> $DIR/manual_find_map.rs:9:19
    |
 LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_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_find_map.rs:8:28
+  --> $DIR/manual_find_map.rs:9:28
    |
 LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                            ^^^^^^^^^^
@@ -13,31 +13,31 @@ LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()
    = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:11:19
+  --> $DIR/manual_find_map.rs:12:19
    |
 LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_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_find_map.rs:11:29
+  --> $DIR/manual_find_map.rs:12:29
    |
 LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:14:19
+  --> $DIR/manual_find_map.rs:15:19
    |
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_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_find_map.rs:14:29
+  --> $DIR/manual_find_map.rs:15:29
    |
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:17:10
+  --> $DIR/manual_find_map.rs:18:10
    |
 LL |           .find(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
@@ -45,13 +45,13 @@ LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_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_find_map.rs:17:20
+  --> $DIR/manual_find_map.rs:18:20
    |
 LL |         .find(|&x| to_ref(to_opt(x)).is_some())
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:20:10
+  --> $DIR/manual_find_map.rs:21:10
    |
 LL |           .find(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
@@ -59,13 +59,13 @@ LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_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_find_map.rs:20:19
+  --> $DIR/manual_find_map.rs:21:19
    |
 LL |         .find(|x| to_ref(to_opt(*x)).is_some())
    |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:24:10
+  --> $DIR/manual_find_map.rs:25:10
    |
 LL |           .find(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
@@ -73,13 +73,13 @@ LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_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_find_map.rs:24:20
+  --> $DIR/manual_find_map.rs:25:20
    |
 LL |         .find(|&x| to_ref(to_res(x)).is_ok())
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:27:10
+  --> $DIR/manual_find_map.rs:28:10
    |
 LL |           .find(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
@@ -87,109 +87,109 @@ LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_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_find_map.rs:27:19
+  --> $DIR/manual_find_map.rs:28:19
    |
 LL |         .find(|x| to_ref(to_res(*x)).is_ok())
    |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:33:26
+  --> $DIR/manual_find_map.rs:34:26
    |
 LL |     iter::<Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:34:27
+  --> $DIR/manual_find_map.rs:35:27
    |
 LL |     iter::<&Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:35:28
+  --> $DIR/manual_find_map.rs:36:28
    |
 LL |     iter::<&&Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:36:27
+  --> $DIR/manual_find_map.rs:37:27
    |
 LL |     iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:37:28
+  --> $DIR/manual_find_map.rs:38:28
    |
 LL |     iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:38:31
+  --> $DIR/manual_find_map.rs:39:31
    |
 LL |     iter::<&Option<String>>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:39:31
+  --> $DIR/manual_find_map.rs:40:31
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
    |
 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_find_map.rs:39:41
+  --> $DIR/manual_find_map.rs:40:41
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:41:30
+  --> $DIR/manual_find_map.rs:42:30
    |
 LL |     iter::<Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:42:31
+  --> $DIR/manual_find_map.rs:43:31
    |
 LL |     iter::<&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:43:32
+  --> $DIR/manual_find_map.rs:44:32
    |
 LL |     iter::<&&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:44:31
+  --> $DIR/manual_find_map.rs:45:31
    |
 LL |     iter::<Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:45:32
+  --> $DIR/manual_find_map.rs:46:32
    |
 LL |     iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:46:35
+  --> $DIR/manual_find_map.rs:47:35
    |
 LL |     iter::<&Result<String, ()>>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:47:35
+  --> $DIR/manual_find_map.rs:48:35
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().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_find_map.rs:47:45
+  --> $DIR/manual_find_map.rs:48:45
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:95:10
+  --> $DIR/manual_find_map.rs:96:10
    |
 LL |           .find(|f| f.option_field.is_some())
    |  __________^
@@ -197,7 +197,7 @@ LL | |         .map(|f| f.option_field.clone().unwrap());
    | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:100:10
+  --> $DIR/manual_find_map.rs:101:10
    |
 LL |           .find(|f| f.ref_field.is_some())
    |  __________^
@@ -205,7 +205,7 @@ LL | |         .map(|f| f.ref_field.cloned().unwrap());
    | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:105:10
+  --> $DIR/manual_find_map.rs:106:10
    |
 LL |           .find(|f| f.ref_field.is_some())
    |  __________^
@@ -213,7 +213,7 @@ LL | |         .map(|f| f.ref_field.copied().unwrap());
    | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:110:10
+  --> $DIR/manual_find_map.rs:111:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -221,7 +221,7 @@ LL | |         .map(|f| f.result_field.clone().unwrap());
    | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:115:10
+  --> $DIR/manual_find_map.rs:116:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -229,7 +229,7 @@ LL | |         .map(|f| f.result_field.as_ref().unwrap());
    | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:120:10
+  --> $DIR/manual_find_map.rs:121:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -237,7 +237,7 @@ LL | |         .map(|f| f.result_field.as_deref().unwrap());
    | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:125:10
+  --> $DIR/manual_find_map.rs:126:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -245,7 +245,7 @@ LL | |         .map(|f| f.result_field.as_mut().unwrap());
    | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:130:10
+  --> $DIR/manual_find_map.rs:131:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -253,7 +253,7 @@ LL | |         .map(|f| f.result_field.as_deref_mut().unwrap());
    | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:135:10
+  --> $DIR/manual_find_map.rs:136:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
diff --git a/tests/ui/min_ident_chars.rs b/tests/ui/min_ident_chars.rs
index 030863ca0d3..f99c35d5c57 100644
--- a/tests/ui/min_ident_chars.rs
+++ b/tests/ui/min_ident_chars.rs
@@ -1,5 +1,6 @@
 //@aux-build:proc_macros.rs
 #![allow(irrefutable_let_patterns, nonstandard_style, unused)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::min_ident_chars)]
 
 extern crate proc_macros;
diff --git a/tests/ui/min_ident_chars.stderr b/tests/ui/min_ident_chars.stderr
index 253636cf91d..e4181157ea2 100644
--- a/tests/ui/min_ident_chars.stderr
+++ b/tests/ui/min_ident_chars.stderr
@@ -1,5 +1,5 @@
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:8:8
+  --> $DIR/min_ident_chars.rs:9:8
    |
 LL | struct A {
    |        ^
@@ -8,169 +8,169 @@ LL | struct A {
    = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]`
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:9:5
+  --> $DIR/min_ident_chars.rs:10:5
    |
 LL |     a: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:11:5
+  --> $DIR/min_ident_chars.rs:12:5
    |
 LL |     A: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:12:5
+  --> $DIR/min_ident_chars.rs:13:5
    |
 LL |     I: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:15:8
+  --> $DIR/min_ident_chars.rs:16:8
    |
 LL | struct B(u32);
    |        ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:17:8
+  --> $DIR/min_ident_chars.rs:18:8
    |
 LL | struct O {
    |        ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:18:5
+  --> $DIR/min_ident_chars.rs:19:5
    |
 LL |     o: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:23:6
+  --> $DIR/min_ident_chars.rs:24:6
    |
 LL | enum C {
    |      ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:24:5
+  --> $DIR/min_ident_chars.rs:25:5
    |
 LL |     D,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:25:5
+  --> $DIR/min_ident_chars.rs:26:5
    |
 LL |     E,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:26:5
+  --> $DIR/min_ident_chars.rs:27:5
    |
 LL |     F,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:50:9
+  --> $DIR/min_ident_chars.rs:51:9
    |
 LL |     let h = 1;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:51:9
+  --> $DIR/min_ident_chars.rs:52:9
    |
 LL |     let e = 2;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:52:9
+  --> $DIR/min_ident_chars.rs:53:9
    |
 LL |     let l = 3;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:53:9
+  --> $DIR/min_ident_chars.rs:54:9
    |
 LL |     let l = 4;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:54:9
+  --> $DIR/min_ident_chars.rs:55:9
    |
 LL |     let o = 6;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:58:10
+  --> $DIR/min_ident_chars.rs:59:10
    |
 LL |     let (h, o, w) = (1, 2, 3);
    |          ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:58:13
+  --> $DIR/min_ident_chars.rs:59:13
    |
 LL |     let (h, o, w) = (1, 2, 3);
    |             ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:59:10
+  --> $DIR/min_ident_chars.rs:60:10
    |
 LL |     for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
    |          ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:59:14
+  --> $DIR/min_ident_chars.rs:60:14
    |
 LL |     for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
    |              ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:59:17
+  --> $DIR/min_ident_chars.rs:60:17
    |
 LL |     for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
    |                 ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:61:16
+  --> $DIR/min_ident_chars.rs:62:16
    |
 LL |     while let (d, o, _i, n, g) = (true, true, false, false, true) {}
    |                ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:61:19
+  --> $DIR/min_ident_chars.rs:62:19
    |
 LL |     while let (d, o, _i, n, g) = (true, true, false, false, true) {}
    |                   ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:61:29
+  --> $DIR/min_ident_chars.rs:62:29
    |
 LL |     while let (d, o, _i, n, g) = (true, true, false, false, true) {}
    |                             ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:65:9
+  --> $DIR/min_ident_chars.rs:66:9
    |
 LL |     let o = 1;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:66:9
+  --> $DIR/min_ident_chars.rs:67:9
    |
 LL |     let o = O { o };
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:80:4
+  --> $DIR/min_ident_chars.rs:81:4
    |
 LL | fn b() {}
    |    ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:81:21
+  --> $DIR/min_ident_chars.rs:82:21
    |
 LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
    |                     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:81:29
+  --> $DIR/min_ident_chars.rs:82:29
    |
 LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
    |                             ^
diff --git a/tests/ui/misnamed_getters.fixed b/tests/ui/misnamed_getters.fixed
index 2a7a2067ee0..70af604b214 100644
--- a/tests/ui/misnamed_getters.fixed
+++ b/tests/ui/misnamed_getters.fixed
@@ -1,4 +1,5 @@
 #![allow(unused)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::misnamed_getters)]
 
 struct A {
diff --git a/tests/ui/misnamed_getters.rs b/tests/ui/misnamed_getters.rs
index 56ddc46c4d4..23c3e7bc5cf 100644
--- a/tests/ui/misnamed_getters.rs
+++ b/tests/ui/misnamed_getters.rs
@@ -1,4 +1,5 @@
 #![allow(unused)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::misnamed_getters)]
 
 struct A {
diff --git a/tests/ui/misnamed_getters.stderr b/tests/ui/misnamed_getters.stderr
index aadec654908..120a3f3112e 100644
--- a/tests/ui/misnamed_getters.stderr
+++ b/tests/ui/misnamed_getters.stderr
@@ -1,5 +1,5 @@
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:11:5
+  --> $DIR/misnamed_getters.rs:12:5
    |
 LL | /     fn a(&self) -> &u8 {
 LL | |
@@ -13,7 +13,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]`
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:16:5
+  --> $DIR/misnamed_getters.rs:17:5
    |
 LL | /     fn a_mut(&mut self) -> &mut u8 {
 LL | |
@@ -23,7 +23,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:21:5
+  --> $DIR/misnamed_getters.rs:22:5
    |
 LL | /     fn b(self) -> u8 {
 LL | |
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:26:5
+  --> $DIR/misnamed_getters.rs:27:5
    |
 LL | /     fn b_mut(&mut self) -> &mut u8 {
 LL | |
@@ -43,7 +43,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:31:5
+  --> $DIR/misnamed_getters.rs:32:5
    |
 LL | /     fn c(&self) -> &u8 {
 LL | |
@@ -53,7 +53,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:36:5
+  --> $DIR/misnamed_getters.rs:37:5
    |
 LL | /     fn c_mut(&mut self) -> &mut u8 {
 LL | |
@@ -63,7 +63,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:48:5
+  --> $DIR/misnamed_getters.rs:49:5
    |
 LL | /     unsafe fn a(&self) -> &u8 {
 LL | |
@@ -73,7 +73,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:52:5
+  --> $DIR/misnamed_getters.rs:53:5
    |
 LL | /     unsafe fn a_mut(&mut self) -> &mut u8 {
 LL | |
@@ -83,7 +83,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:57:5
+  --> $DIR/misnamed_getters.rs:58:5
    |
 LL | /     unsafe fn b(self) -> u8 {
 LL | |
@@ -93,7 +93,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:62:5
+  --> $DIR/misnamed_getters.rs:63:5
    |
 LL | /     unsafe fn b_mut(&mut self) -> &mut u8 {
 LL | |
@@ -103,7 +103,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:75:5
+  --> $DIR/misnamed_getters.rs:76:5
    |
 LL | /     unsafe fn a_unchecked(&self) -> &u8 {
 LL | |
@@ -113,7 +113,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:79:5
+  --> $DIR/misnamed_getters.rs:80:5
    |
 LL | /     unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
 LL | |
@@ -123,7 +123,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:84:5
+  --> $DIR/misnamed_getters.rs:85:5
    |
 LL | /     unsafe fn b_unchecked(self) -> u8 {
 LL | |
@@ -133,7 +133,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:89:5
+  --> $DIR/misnamed_getters.rs:90:5
    |
 LL | /     unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
 LL | |
@@ -143,7 +143,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:122:5
+  --> $DIR/misnamed_getters.rs:123:5
    |
 LL | /     fn a(&self) -> &u8 {
 LL | |
@@ -153,7 +153,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:126:5
+  --> $DIR/misnamed_getters.rs:127:5
    |
 LL | /     fn a_mut(&mut self) -> &mut u8 {
 LL | |
@@ -163,7 +163,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:131:5
+  --> $DIR/misnamed_getters.rs:132:5
    |
 LL | /     fn d(&self) -> &u8 {
 LL | |
@@ -173,7 +173,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:135:5
+  --> $DIR/misnamed_getters.rs:136:5
    |
 LL | /     fn d_mut(&mut self) -> &mut u8 {
 LL | |
diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed
index c9ea831f8b2..3059de8f89c 100644
--- a/tests/ui/needless_bool/fixable.fixed
+++ b/tests/ui/needless_bool/fixable.fixed
@@ -7,7 +7,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::needless_return,
-    clippy::self_named_constructors
+    clippy::self_named_constructors,
+    clippy::struct_field_names
 )]
 
 use std::cell::Cell;
diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs
index b83d9c3f209..b2cbe86e223 100644
--- a/tests/ui/needless_bool/fixable.rs
+++ b/tests/ui/needless_bool/fixable.rs
@@ -7,7 +7,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::needless_return,
-    clippy::self_named_constructors
+    clippy::self_named_constructors,
+    clippy::struct_field_names
 )]
 
 use std::cell::Cell;
diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr
index 2b189c89851..72b0670c95b 100644
--- a/tests/ui/needless_bool/fixable.stderr
+++ b/tests/ui/needless_bool/fixable.stderr
@@ -1,5 +1,5 @@
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:40:5
+  --> $DIR/fixable.rs:41:5
    |
 LL | /     if x {
 LL | |         true
@@ -12,7 +12,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:45:5
+  --> $DIR/fixable.rs:46:5
    |
 LL | /     if x {
 LL | |         false
@@ -22,7 +22,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:50:5
+  --> $DIR/fixable.rs:51:5
    |
 LL | /     if x && y {
 LL | |         false
@@ -32,7 +32,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `!(x && y)`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:58:5
+  --> $DIR/fixable.rs:59:5
    |
 LL | /     if a == b {
 LL | |         false
@@ -42,7 +42,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a != b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:63:5
+  --> $DIR/fixable.rs:64:5
    |
 LL | /     if a != b {
 LL | |         false
@@ -52,7 +52,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a == b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:68:5
+  --> $DIR/fixable.rs:69:5
    |
 LL | /     if a < b {
 LL | |         false
@@ -62,7 +62,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a >= b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:73:5
+  --> $DIR/fixable.rs:74:5
    |
 LL | /     if a <= b {
 LL | |         false
@@ -72,7 +72,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a > b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:78:5
+  --> $DIR/fixable.rs:79:5
    |
 LL | /     if a > b {
 LL | |         false
@@ -82,7 +82,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a <= b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:83:5
+  --> $DIR/fixable.rs:84:5
    |
 LL | /     if a >= b {
 LL | |         false
@@ -92,7 +92,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a < b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:111:5
+  --> $DIR/fixable.rs:112:5
    |
 LL | /     if x {
 LL | |         return true;
@@ -102,7 +102,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:119:5
+  --> $DIR/fixable.rs:120:5
    |
 LL | /     if x {
 LL | |         return false;
@@ -112,7 +112,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return !x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:127:5
+  --> $DIR/fixable.rs:128:5
    |
 LL | /     if x && y {
 LL | |         return true;
@@ -122,7 +122,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return x && y`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:135:5
+  --> $DIR/fixable.rs:136:5
    |
 LL | /     if x && y {
 LL | |         return false;
@@ -132,7 +132,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return !(x && y)`
 
 error: equality checks against true are unnecessary
-  --> $DIR/fixable.rs:143:8
+  --> $DIR/fixable.rs:144:8
    |
 LL |     if x == true {};
    |        ^^^^^^^^^ help: try simplifying it as shown: `x`
@@ -141,25 +141,25 @@ LL |     if x == true {};
    = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/fixable.rs:147:8
+  --> $DIR/fixable.rs:148:8
    |
 LL |     if x == false {};
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: equality checks against true are unnecessary
-  --> $DIR/fixable.rs:157:8
+  --> $DIR/fixable.rs:158:8
    |
 LL |     if x == true {};
    |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/fixable.rs:158:8
+  --> $DIR/fixable.rs:159:8
    |
 LL |     if x == false {};
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:167:12
+  --> $DIR/fixable.rs:168:12
    |
 LL |       } else if returns_bool() {
    |  ____________^
@@ -170,7 +170,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `{ !returns_bool() }`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:180:5
+  --> $DIR/fixable.rs:181:5
    |
 LL | /     if unsafe { no(4) } & 1 != 0 {
 LL | |         true
@@ -180,13 +180,13 @@ LL | |     };
    | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:185:30
+  --> $DIR/fixable.rs:186:30
    |
 LL |     let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:188:9
+  --> $DIR/fixable.rs:189:9
    |
 LL |         if unsafe { no(4) } & 1 != 0 { true } else { false }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
diff --git a/tests/ui/rest_pat_in_fully_bound_structs.rs b/tests/ui/rest_pat_in_fully_bound_structs.rs
index e25609f7560..51fe346d092 100644
--- a/tests/ui/rest_pat_in_fully_bound_structs.rs
+++ b/tests/ui/rest_pat_in_fully_bound_structs.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::rest_pat_in_fully_bound_structs)]
+#![allow(clippy::struct_field_names)]
 
 struct A {
     a: i32,
diff --git a/tests/ui/rest_pat_in_fully_bound_structs.stderr b/tests/ui/rest_pat_in_fully_bound_structs.stderr
index 2c221b4dbb2..a62f1d0b65f 100644
--- a/tests/ui/rest_pat_in_fully_bound_structs.stderr
+++ b/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -1,5 +1,5 @@
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
-  --> $DIR/rest_pat_in_fully_bound_structs.rs:22:9
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:23:9
    |
 LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
    = help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]`
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
-  --> $DIR/rest_pat_in_fully_bound_structs.rs:24:9
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:25:9
    |
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    = help: consider removing `..` from this binding
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
-  --> $DIR/rest_pat_in_fully_bound_structs.rs:31:9
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:32:9
    |
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/struct_fields.rs b/tests/ui/struct_fields.rs
new file mode 100644
index 00000000000..8b1a1446e3c
--- /dev/null
+++ b/tests/ui/struct_fields.rs
@@ -0,0 +1,331 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::struct_field_names)]
+#![allow(unused)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct Data1 {
+    field_data1: u8,
+    //~^ ERROR: field name ends with the struct's name
+    another: u8,
+    foo: u8,
+    bar: u8,
+}
+
+struct Data2 {
+    another: u8,
+    foo: u8,
+    data2_field: u8,
+    //~^ ERROR: field name starts with the struct's name
+    bar: u8,
+}
+
+struct StructData {
+    //~^ ERROR: all fields have the same postfix: `data`
+    movable_data: u8,
+    fixed_data: u8,
+    invisible_data: u8,
+}
+
+struct DataStruct {
+    //~^ ERROR: all fields have the same prefix: `data`
+    data_movable: u8,
+    data_fixed: u8,
+    data_invisible: u8,
+}
+
+struct DoublePrefix {
+    //~^ ERROR: all fields have the same prefix: `some_data`
+    some_data_a: bool,
+    some_data_b: bool,
+    some_data_c: bool,
+}
+
+struct DoublePostfix {
+    //~^ ERROR: all fields have the same postfix: `some_data`
+    a_some_data: bool,
+    b_some_data: bool,
+    c_some_data: bool,
+}
+
+#[allow(non_snake_case)]
+struct NotSnakeCase {
+    //~^ ERROR: all fields have the same postfix: `someData`
+    a_someData: bool,
+    b_someData: bool,
+    c_someData: bool,
+}
+#[allow(non_snake_case)]
+struct NotSnakeCase2 {
+    //~^ ERROR: all fields have the same prefix: `someData`
+    someData_c: bool,
+    someData_b: bool,
+    someData_a_b: bool,
+}
+
+// no error, threshold is 3 fiels by default
+struct Fooo {
+    foo: u8,
+    bar: u8,
+}
+
+struct NonCaps {
+    //~^ ERROR: all fields have the same prefix: `prefix`
+    prefix_的: u8,
+    prefix_tea: u8,
+    prefix_cake: u8,
+}
+
+// should not lint
+#[allow(clippy::struct_field_names)]
+pub mod allowed {
+    pub struct PubAllowed {
+        some_this: u8,
+        some_that: u8,
+        some_other_what: u8,
+    }
+}
+
+// should not lint
+struct SomeData {
+    foo: u8,
+    bar: bool,
+    path: u8,
+    answer: u8,
+}
+
+// should not lint
+pub struct NetworkLayer {
+    layer1: Vec<u8>,
+    layer2: Vec<u8>,
+    layer3: Vec<u8>,
+    layer4: Vec<u8>,
+}
+
+//should not lint
+struct North {
+    normal: u8,
+    no_left: u8,
+    no_right: u8,
+}
+
+mod issue8324_from_enum_variant_names {
+    // 8324: enum_variant_names warns even if removing the suffix would leave an empty string
+    struct Phase {
+        pre_lookup: u8,
+        lookup: u8,
+        post_lookup: u8,
+    }
+}
+
+mod issue9018_from_enum_variant_names {
+    struct DoLint {
+        //~^ ERROR: all fields have the same prefix: `_type`
+        _type_create: u8,
+        _type_read: u8,
+        _type_update: u8,
+        _type_destroy: u8,
+    }
+
+    struct DoLint2 {
+        //~^ ERROR: all fields have the same prefix: `__type`
+        __type_create: u8,
+        __type_read: u8,
+        __type_update: u8,
+        __type_destroy: u8,
+    }
+
+    struct DoLint3 {
+        //~^ ERROR: all fields have the same prefix: `___type`
+        ___type_create: u8,
+        ___type_read: u8,
+        ___type_update: u8,
+        ___type_destroy: u8,
+    }
+
+    struct DoLint4 {
+        //~^ ERROR: all fields have the same postfix: `_`
+        create_: u8,
+        read_: u8,
+        update_: u8,
+        destroy_: u8,
+    }
+
+    struct DoLint5 {
+        //~^ ERROR: all fields have the same postfix: `__`
+        create__: u8,
+        read__: u8,
+        update__: u8,
+        destroy__: u8,
+    }
+
+    struct DoLint6 {
+        //~^ ERROR: all fields have the same postfix: `___`
+        create___: u8,
+        read___: u8,
+        update___: u8,
+        destroy___: u8,
+    }
+
+    struct DoLintToo {
+        //~^ ERROR: all fields have the same postfix: `type`
+        _create_type: u8,
+        _update_type: u8,
+        _delete_type: u8,
+    }
+
+    struct DoNotLint {
+        _foo: u8,
+        _bar: u8,
+        _baz: u8,
+    }
+
+    struct DoNotLint2 {
+        __foo: u8,
+        __bar: u8,
+        __baz: u8,
+    }
+}
+
+mod allow_attributes_on_fields {
+    struct Struct {
+        #[allow(clippy::struct_field_names)]
+        struct_starts_with: u8,
+        #[allow(clippy::struct_field_names)]
+        ends_with_struct: u8,
+        foo: u8,
+    }
+}
+
+// food field should not lint
+struct Foo {
+    food: i32,
+    a: i32,
+    b: i32,
+}
+
+struct Proxy {
+    proxy: i32,
+    //~^ ERROR: field name starts with the struct's name
+    unrelated1: bool,
+    unrelated2: bool,
+}
+
+// should not lint
+pub struct RegexT {
+    __buffer: i32,
+    __allocated: i32,
+    __used: i32,
+}
+
+mod macro_tests {
+    macro_rules! mk_struct {
+        () => {
+            struct MacroStruct {
+                some_a: i32,
+                some_b: i32,
+                some_c: i32,
+            }
+        };
+    }
+    mk_struct!();
+    //~^ ERROR: all fields have the same prefix: `some`
+
+    macro_rules! mk_struct2 {
+        () => {
+            struct Macrobaz {
+                macrobaz_a: i32,
+                some_b: i32,
+                some_c: i32,
+            }
+        };
+    }
+    mk_struct2!();
+    //~^ ERROR: field name starts with the struct's name
+
+    macro_rules! mk_struct_with_names {
+        ($struct_name:ident, $field:ident) => {
+            struct $struct_name {
+                $field: i32,
+                other_something: i32,
+                other_field: i32,
+            }
+        };
+    }
+    // expands to `struct Foo { foo: i32, ... }`
+    mk_struct_with_names!(Foo, foo);
+    //~^ ERROR: field name starts with the struct's name
+
+    // expands to a struct with all fields starting with `other` but should not
+    // be linted because some fields come from the macro definition and the other from the input
+    mk_struct_with_names!(Some, other_data);
+
+    // should not lint when names come from different places
+    macro_rules! mk_struct_with_field_name {
+        ($field_name:ident) => {
+            struct Baz {
+                one: i32,
+                two: i32,
+                $field_name: i32,
+            }
+        };
+    }
+    mk_struct_with_field_name!(baz_three);
+
+    // should not lint when names come from different places
+    macro_rules! mk_struct_with_field_name {
+        ($field_name:ident) => {
+            struct Bazilisk {
+                baz_one: i32,
+                baz_two: i32,
+                $field_name: i32,
+            }
+        };
+    }
+    mk_struct_with_field_name!(baz_three);
+
+    macro_rules! mk_struct_full_def {
+        ($struct_name:ident, $field1:ident, $field2:ident, $field3:ident) => {
+            struct $struct_name {
+                $field1: i32,
+                $field2: i32,
+                $field3: i32,
+            }
+        };
+    }
+    mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
+    //~^ ERROR: all fields have the same prefix: `some`
+}
+
+// should not lint on external code
+external! {
+    struct DataExternal {
+        field_data1: u8,
+        another: u8,
+        foo: u8,
+        bar: u8,
+    }
+
+    struct NotSnakeCaseExternal {
+        someData_c: bool,
+        someData_b: bool,
+        someData_a_b: bool,
+    }
+
+    struct DoublePrefixExternal {
+        some_data_a: bool,
+        some_data_b: bool,
+        some_data_c: bool,
+    }
+
+    struct StructDataExternal {
+        movable_data: u8,
+        fixed_data: u8,
+        invisible_data: u8,
+    }
+
+}
+
+fn main() {}
diff --git a/tests/ui/struct_fields.stderr b/tests/ui/struct_fields.stderr
new file mode 100644
index 00000000000..4ca57715b18
--- /dev/null
+++ b/tests/ui/struct_fields.stderr
@@ -0,0 +1,265 @@
+error: field name ends with the struct's name
+  --> $DIR/struct_fields.rs:10:5
+   |
+LL |     field_data1: u8,
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::struct-field-names` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]`
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:20:5
+   |
+LL |     data2_field: u8,
+   |     ^^^^^^^^^^^^^^^
+
+error: all fields have the same postfix: `data`
+  --> $DIR/struct_fields.rs:25:1
+   |
+LL | / struct StructData {
+LL | |
+LL | |     movable_data: u8,
+LL | |     fixed_data: u8,
+LL | |     invisible_data: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same prefix: `data`
+  --> $DIR/struct_fields.rs:32:1
+   |
+LL | / struct DataStruct {
+LL | |
+LL | |     data_movable: u8,
+LL | |     data_fixed: u8,
+LL | |     data_invisible: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `some_data`
+  --> $DIR/struct_fields.rs:39:1
+   |
+LL | / struct DoublePrefix {
+LL | |
+LL | |     some_data_a: bool,
+LL | |     some_data_b: bool,
+LL | |     some_data_c: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same postfix: `some_data`
+  --> $DIR/struct_fields.rs:46:1
+   |
+LL | / struct DoublePostfix {
+LL | |
+LL | |     a_some_data: bool,
+LL | |     b_some_data: bool,
+LL | |     c_some_data: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `someData`
+  --> $DIR/struct_fields.rs:54:1
+   |
+LL | / struct NotSnakeCase {
+LL | |
+LL | |     a_someData: bool,
+LL | |     b_someData: bool,
+LL | |     c_someData: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same prefix: `someData`
+  --> $DIR/struct_fields.rs:61:1
+   |
+LL | / struct NotSnakeCase2 {
+LL | |
+LL | |     someData_c: bool,
+LL | |     someData_b: bool,
+LL | |     someData_a_b: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `prefix`
+  --> $DIR/struct_fields.rs:74:1
+   |
+LL | / struct NonCaps {
+LL | |
+LL | |     prefix_的: u8,
+LL | |     prefix_tea: u8,
+LL | |     prefix_cake: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `_type`
+  --> $DIR/struct_fields.rs:124:5
+   |
+LL | /     struct DoLint {
+LL | |
+LL | |         _type_create: u8,
+LL | |         _type_read: u8,
+LL | |         _type_update: u8,
+LL | |         _type_destroy: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `__type`
+  --> $DIR/struct_fields.rs:132:5
+   |
+LL | /     struct DoLint2 {
+LL | |
+LL | |         __type_create: u8,
+LL | |         __type_read: u8,
+LL | |         __type_update: u8,
+LL | |         __type_destroy: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `___type`
+  --> $DIR/struct_fields.rs:140:5
+   |
+LL | /     struct DoLint3 {
+LL | |
+LL | |         ___type_create: u8,
+LL | |         ___type_read: u8,
+LL | |         ___type_update: u8,
+LL | |         ___type_destroy: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same postfix: `_`
+  --> $DIR/struct_fields.rs:148:5
+   |
+LL | /     struct DoLint4 {
+LL | |
+LL | |         create_: u8,
+LL | |         read_: u8,
+LL | |         update_: u8,
+LL | |         destroy_: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `__`
+  --> $DIR/struct_fields.rs:156:5
+   |
+LL | /     struct DoLint5 {
+LL | |
+LL | |         create__: u8,
+LL | |         read__: u8,
+LL | |         update__: u8,
+LL | |         destroy__: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `___`
+  --> $DIR/struct_fields.rs:164:5
+   |
+LL | /     struct DoLint6 {
+LL | |
+LL | |         create___: u8,
+LL | |         read___: u8,
+LL | |         update___: u8,
+LL | |         destroy___: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `type`
+  --> $DIR/struct_fields.rs:172:5
+   |
+LL | /     struct DoLintToo {
+LL | |
+LL | |         _create_type: u8,
+LL | |         _update_type: u8,
+LL | |         _delete_type: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:210:5
+   |
+LL |     proxy: i32,
+   |     ^^^^^^^^^^
+
+error: all fields have the same prefix: `some`
+  --> $DIR/struct_fields.rs:226:13
+   |
+LL | /             struct MacroStruct {
+LL | |                 some_a: i32,
+LL | |                 some_b: i32,
+LL | |                 some_c: i32,
+LL | |             }
+   | |_____________^
+...
+LL |       mk_struct!();
+   |       ------------ in this macro invocation
+   |
+   = help: remove the prefixes
+   = note: this error originates in the macro `mk_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:239:17
+   |
+LL |                 macrobaz_a: i32,
+   |                 ^^^^^^^^^^^^^^^
+...
+LL |     mk_struct2!();
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `mk_struct2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:251:17
+   |
+LL |                 $field: i32,
+   |                 ^^^^^^^^^^^
+...
+LL |     mk_struct_with_names!(Foo, foo);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `mk_struct_with_names` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: all fields have the same prefix: `some`
+  --> $DIR/struct_fields.rs:291:13
+   |
+LL | /             struct $struct_name {
+LL | |                 $field1: i32,
+LL | |                 $field2: i32,
+LL | |                 $field3: i32,
+LL | |             }
+   | |_____________^
+...
+LL |       mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
+   |       ----------------------------------------------------------------- in this macro invocation
+   |
+   = help: remove the prefixes
+   = note: this error originates in the macro `mk_struct_full_def` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 21 previous errors
+