diff options
| author | Andre Bogus <bogusandre@gmail.com> | 2021-12-25 16:52:58 +0100 |
|---|---|---|
| committer | Andre Bogus <bogusandre@gmail.com> | 2021-12-26 16:19:22 +0100 |
| commit | 3ebd2bc2e4fac8f56e1399872ea449594a280daa (patch) | |
| tree | 4ebe86e999fc72653647f338f7f54925104017a0 /clippy_lints/src/init_numbered_fields.rs | |
| parent | 547efad9454123b5d37e627eb8643666aa3ddf3b (diff) | |
| download | rust-3ebd2bc2e4fac8f56e1399872ea449594a280daa.tar.gz rust-3ebd2bc2e4fac8f56e1399872ea449594a280daa.zip | |
new lint: `init-numbered-fields`
Diffstat (limited to 'clippy_lints/src/init_numbered_fields.rs')
| -rw-r--r-- | clippy_lints/src/init_numbered_fields.rs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs new file mode 100644 index 00000000000..5fe6725b581 --- /dev/null +++ b/clippy_lints/src/init_numbered_fields.rs @@ -0,0 +1,80 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::in_macro; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::borrow::Cow; +use std::cmp::Reverse; +use std::collections::BinaryHeap; + +declare_clippy_lint! { + /// ### What it does + /// Checks for tuple structs initialized with field syntax. + /// It will however not lint if a base initializer is present. + /// The lint will also ignore code in macros. + /// + /// ### Why is this bad? + /// This may be confusing to the uninitiated and adds no + /// benefit as opposed to tuple initializers + /// + /// ### Example + /// ```rust + /// struct TupleStruct(u8, u16); + /// + /// let _ = TupleStruct { + /// 0: 1, + /// 1: 23, + /// }; + /// + /// // should be written as + /// let base = TupleStruct(1, 23); + /// + /// // This is OK however + /// let _ = TupleStruct { 0: 42, ..base }; + /// ``` + #[clippy::version = "1.59.0"] + pub INIT_NUMBERED_FIELDS, + style, + "numbered fields in tuple struct initializer" +} + +declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]); + +impl<'tcx> LateLintPass<'tcx> for NumberedFields { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Struct(path, fields, None) = e.kind { + if !fields.is_empty() + && !in_macro(e.span) + && fields + .iter() + .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit)) + { + let expr_spans = fields + .iter() + .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span)) + .collect::<BinaryHeap<_>>(); + let mut appl = Applicability::MachineApplicable; + let snippet = format!( + "{}({})", + snippet_with_applicability(cx, path.span(), "..", &mut appl), + expr_spans + .into_iter_sorted() + .map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl)) + .intersperse(Cow::Borrowed(", ")) + .collect::<String>() + ); + span_lint_and_sugg( + cx, + INIT_NUMBERED_FIELDS, + e.span, + "used a field initializer for a tuple struct", + "try this instead", + snippet, + appl, + ); + } + } + } +} |
