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