1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet_with_applicability;
3 use rustc_errors::Applicability;
4 use rustc_hir::def::{DefKind, Res};
5 use rustc_hir::{Expr, ExprKind};
6 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
10 use std::collections::BinaryHeap;
12 declare_clippy_lint! {
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.
18 /// ### Why is this bad?
19 /// This may be confusing to the uninitiated and adds no
20 /// benefit as opposed to tuple initializers
24 /// struct TupleStruct(u8, u16);
26 /// let _ = TupleStruct {
31 /// // should be written as
32 /// let base = TupleStruct(1, 23);
34 /// // This is OK however
35 /// let _ = TupleStruct { 0: 42, ..base };
37 #[clippy::version = "1.59.0"]
38 pub INIT_NUMBERED_FIELDS,
40 "numbered fields in tuple struct initializer"
43 declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
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 {
49 && !e.span.from_expansion()
52 .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
53 && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
55 let expr_spans = fields
57 .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
58 .collect::<BinaryHeap<_>>();
59 let mut appl = Applicability::MachineApplicable;
60 let snippet = format!(
62 snippet_with_applicability(cx, path.span(), "..", &mut appl),
65 .map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl))
66 .intersperse(Cow::Borrowed(", "))
73 "used a field initializer for a tuple struct",