]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/init_numbered_fields.rs
Change `unnecessary_to_owned` `into_iter` suggestions to `MaybeIncorrect`
[rust.git] / clippy_lints / src / init_numbered_fields.rs
1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::in_macro;
3 use clippy_utils::source::snippet_with_applicability;
4 use rustc_errors::Applicability;
5 use rustc_hir::{Expr, ExprKind};
6 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
8 use std::borrow::Cow;
9 use std::cmp::Reverse;
10 use std::collections::BinaryHeap;
11
12 declare_clippy_lint! {
13     /// ### What it does
14     /// Checks for tuple structs initialized with field syntax.
15     /// It will however not lint if a base initializer is present.
16     /// The lint will also ignore code in macros.
17     ///
18     /// ### Why is this bad?
19     /// This may be confusing to the uninitiated and adds no
20     /// benefit as opposed to tuple initializers
21     ///
22     /// ### Example
23     /// ```rust
24     /// struct TupleStruct(u8, u16);
25     ///
26     /// let _ = TupleStruct {
27     ///     0: 1,
28     ///     1: 23,
29     /// };
30     ///
31     /// // should be written as
32     /// let base = TupleStruct(1, 23);
33     ///
34     /// // This is OK however
35     /// let _ = TupleStruct { 0: 42, ..base };
36     /// ```
37     #[clippy::version = "1.59.0"]
38     pub INIT_NUMBERED_FIELDS,
39     style,
40     "numbered fields in tuple struct initializer"
41 }
42
43 declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
44
45 impl<'tcx> LateLintPass<'tcx> for NumberedFields {
46     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
47         if let ExprKind::Struct(path, fields, None) = e.kind {
48             if !fields.is_empty()
49                 && !in_macro(e.span)
50                 && fields
51                     .iter()
52                     .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
53             {
54                 let expr_spans = fields
55                     .iter()
56                     .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
57                     .collect::<BinaryHeap<_>>();
58                 let mut appl = Applicability::MachineApplicable;
59                 let snippet = format!(
60                     "{}({})",
61                     snippet_with_applicability(cx, path.span(), "..", &mut appl),
62                     expr_spans
63                         .into_iter_sorted()
64                         .map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl))
65                         .intersperse(Cow::Borrowed(", "))
66                         .collect::<String>()
67                 );
68                 span_lint_and_sugg(
69                     cx,
70                     INIT_NUMBERED_FIELDS,
71                     e.span,
72                     "used a field initializer for a tuple struct",
73                     "try this instead",
74                     snippet,
75                     appl,
76                 );
77             }
78         }
79     }
80 }