]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/redundant_field_names.rs
Rollup merge of #94113 - Mizobrook-kan:issue-94025, r=estebank
[rust.git] / src / tools / clippy / clippy_lints / src / redundant_field_names.rs
1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::{meets_msrv, msrvs};
3 use rustc_ast::ast::{Expr, ExprKind};
4 use rustc_errors::Applicability;
5 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
6 use rustc_middle::lint::in_external_macro;
7 use rustc_semver::RustcVersion;
8 use rustc_session::{declare_tool_lint, impl_lint_pass};
9
10 declare_clippy_lint! {
11     /// ### What it does
12     /// Checks for fields in struct literals where shorthands
13     /// could be used.
14     ///
15     /// ### Why is this bad?
16     /// If the field and variable names are the same,
17     /// the field name is redundant.
18     ///
19     /// ### Example
20     /// ```rust
21     /// let bar: u8 = 123;
22     ///
23     /// struct Foo {
24     ///     bar: u8,
25     /// }
26     ///
27     /// let foo = Foo { bar: bar };
28     /// ```
29     /// the last line can be simplified to
30     /// ```ignore
31     /// let foo = Foo { bar };
32     /// ```
33     #[clippy::version = "pre 1.29.0"]
34     pub REDUNDANT_FIELD_NAMES,
35     style,
36     "checks for fields in struct literals where shorthands could be used"
37 }
38
39 pub struct RedundantFieldNames {
40     msrv: Option<RustcVersion>,
41 }
42
43 impl RedundantFieldNames {
44     #[must_use]
45     pub fn new(msrv: Option<RustcVersion>) -> Self {
46         Self { msrv }
47     }
48 }
49
50 impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
51
52 impl EarlyLintPass for RedundantFieldNames {
53     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
54         if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) {
55             return;
56         }
57
58         if in_external_macro(cx.sess(), expr.span) {
59             return;
60         }
61         if let ExprKind::Struct(ref se) = expr.kind {
62             for field in &se.fields {
63                 if field.is_shorthand {
64                     continue;
65                 }
66                 if let ExprKind::Path(None, path) = &field.expr.kind {
67                     if path.segments.len() == 1
68                         && path.segments[0].ident == field.ident
69                         && path.segments[0].args.is_none()
70                     {
71                         span_lint_and_sugg(
72                             cx,
73                             REDUNDANT_FIELD_NAMES,
74                             field.span,
75                             "redundant field names in struct initialization",
76                             "replace it with",
77                             field.ident.to_string(),
78                             Applicability::MachineApplicable,
79                         );
80                     }
81                 }
82             }
83         }
84     }
85     extract_msrv_attr!(EarlyContext);
86 }