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