]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/redundant_field_names.rs
Merge remote-tracking branch 'upstream/master' into rustup
[rust.git] / clippy_lints / src / redundant_field_names.rs
1 use crate::utils::{meets_msrv, span_lint_and_sugg};
2 use rustc_ast::ast::{Expr, ExprKind};
3 use rustc_errors::Applicability;
4 use rustc_lint::{EarlyContext, EarlyLintPass};
5 use rustc_middle::lint::in_external_macro;
6 use rustc_semver::RustcVersion;
7 use rustc_session::{declare_tool_lint, impl_lint_pass};
8
9 const REDUNDANT_FIELD_NAMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0);
10
11 declare_clippy_lint! {
12     /// **What it does:** Checks for fields in struct literals where shorthands
13     /// could be used.
14     ///
15     /// **Why is this bad?** If the field and variable names are the same,
16     /// the field name is redundant.
17     ///
18     /// **Known problems:** None.
19     ///
20     /// **Example:**
21     /// ```rust
22     /// let bar: u8 = 123;
23     ///
24     /// struct Foo {
25     ///     bar: u8,
26     /// }
27     ///
28     /// let foo = Foo { bar: bar };
29     /// ```
30     /// the last line can be simplified to
31     /// ```ignore
32     /// let foo = Foo { bar };
33     /// ```
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(), &REDUNDANT_FIELD_NAMES_MSRV) {
55             return;
56         }
57
58         if in_external_macro(cx.sess, expr.span) {
59             return;
60         }
61         if let ExprKind::Struct(_, ref fields, _) = expr.kind {
62             for field in 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 }