Auto merge of #13068 - Jarcho:init_numbered, r=Alexendoo
Rework `init_numbered_fields` Two behaviour changes: * Not linting in macros * Not linting when side effects might be reordered changelog: `init_numbered_fields`: Don't suggest reordering side effects.
This commit is contained in:
commit
1de41b18d2
@ -1,13 +1,12 @@
|
|||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::{Expr, ExprKind};
|
use rustc_hir::{Expr, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
use rustc_span::SyntaxContext;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::Reverse;
|
|
||||||
use std::collections::BinaryHeap;
|
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for NumberedFields {
|
impl<'tcx> LateLintPass<'tcx> for NumberedFields {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||||
if let ExprKind::Struct(path, fields, None) = e.kind {
|
if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind
|
||||||
if !fields.is_empty()
|
// If the first character of any field is a digit it has to be a tuple.
|
||||||
&& !e.span.from_expansion()
|
&& field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit)
|
||||||
&& fields
|
// Type aliases can't be used as functions.
|
||||||
.iter()
|
&& !matches!(
|
||||||
.all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
|
cx.qpath_res(path, e.hir_id),
|
||||||
&& !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
|
Res::Def(DefKind::TyAlias | DefKind::AssocTy, _)
|
||||||
{
|
)
|
||||||
let expr_spans = fields
|
// This is the only syntax macros can use that works for all struct types.
|
||||||
.iter()
|
&& !e.span.from_expansion()
|
||||||
.map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
|
&& let mut has_side_effects = false
|
||||||
.collect::<BinaryHeap<_>>();
|
&& let Ok(mut expr_spans) = fields
|
||||||
let mut appl = Applicability::MachineApplicable;
|
.iter()
|
||||||
let snippet = format!(
|
.map(|f| {
|
||||||
"{}({})",
|
has_side_effects |= f.expr.can_have_side_effects();
|
||||||
snippet_with_applicability(cx, path.span(), "..", &mut appl),
|
f.ident.as_str().parse::<usize>().map(|x| (x, f.expr.span))
|
||||||
expr_spans
|
})
|
||||||
.into_iter_sorted()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0)
|
// We can only reorder the expressions if there are no side effects.
|
||||||
.intersperse(Cow::Borrowed(", "))
|
&& (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx))
|
||||||
.collect::<String>()
|
{
|
||||||
);
|
span_lint_and_then(
|
||||||
span_lint_and_sugg(
|
cx,
|
||||||
cx,
|
INIT_NUMBERED_FIELDS,
|
||||||
INIT_NUMBERED_FIELDS,
|
e.span,
|
||||||
e.span,
|
"used a field initializer for a tuple struct",
|
||||||
"used a field initializer for a tuple struct",
|
|diag| {
|
||||||
"try",
|
if !has_side_effects {
|
||||||
snippet,
|
// We already checked the order if there are side effects.
|
||||||
appl,
|
expr_spans.sort_by_key(|&(idx, _)| idx);
|
||||||
);
|
}
|
||||||
}
|
let mut app = Applicability::MachineApplicable;
|
||||||
|
diag.span_suggestion(
|
||||||
|
e.span,
|
||||||
|
"use tuple initialization",
|
||||||
|
format!(
|
||||||
|
"{}({})",
|
||||||
|
snippet_with_applicability(cx, path.span(), "..", &mut app),
|
||||||
|
expr_spans
|
||||||
|
.into_iter()
|
||||||
|
.map(
|
||||||
|
|(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0
|
||||||
|
)
|
||||||
|
.intersperse(Cow::Borrowed(", "))
|
||||||
|
.collect::<String>()
|
||||||
|
),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#![feature(f128)]
|
#![feature(f128)]
|
||||||
#![feature(f16)]
|
#![feature(f16)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
#![feature(is_sorted)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
@ -39,4 +39,13 @@ fn main() {
|
|||||||
struct TupleStructVec(Vec<usize>);
|
struct TupleStructVec(Vec<usize>);
|
||||||
|
|
||||||
let _ = TupleStructVec(vec![0, 1, 2, 3]);
|
let _ = TupleStructVec(vec![0, 1, 2, 3]);
|
||||||
|
|
||||||
|
{
|
||||||
|
struct S(i32, i32);
|
||||||
|
let mut iter = [1i32, 1i32].into_iter();
|
||||||
|
let _ = S {
|
||||||
|
1: iter.next().unwrap(),
|
||||||
|
0: iter.next().unwrap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -47,4 +47,13 @@ fn main() {
|
|||||||
struct TupleStructVec(Vec<usize>);
|
struct TupleStructVec(Vec<usize>);
|
||||||
|
|
||||||
let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
|
let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
|
||||||
|
|
||||||
|
{
|
||||||
|
struct S(i32, i32);
|
||||||
|
let mut iter = [1i32, 1i32].into_iter();
|
||||||
|
let _ = S {
|
||||||
|
1: iter.next().unwrap(),
|
||||||
|
0: iter.next().unwrap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
error: used a field initializer for a tuple struct
|
error: used a field initializer for a tuple struct
|
||||||
--> tests/ui/numbered_fields.rs:17:13
|
--> tests/ui/init_numbered_fields.rs:17:13
|
||||||
|
|
|
|
||||||
LL | let _ = TupleStruct {
|
LL | let _ = TupleStruct {
|
||||||
| _____________^
|
| _____________^
|
||||||
@ -7,13 +7,13 @@ LL | | 0: 1u32,
|
|||||||
LL | | 1: 42,
|
LL | | 1: 42,
|
||||||
LL | | 2: 23u8,
|
LL | | 2: 23u8,
|
||||||
LL | | };
|
LL | | };
|
||||||
| |_____^ help: try: `TupleStruct(1u32, 42, 23u8)`
|
| |_____^ help: use tuple initialization: `TupleStruct(1u32, 42, 23u8)`
|
||||||
|
|
|
|
||||||
= note: `-D clippy::init-numbered-fields` implied by `-D warnings`
|
= note: `-D clippy::init-numbered-fields` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]`
|
= help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]`
|
||||||
|
|
||||||
error: used a field initializer for a tuple struct
|
error: used a field initializer for a tuple struct
|
||||||
--> tests/ui/numbered_fields.rs:24:13
|
--> tests/ui/init_numbered_fields.rs:24:13
|
||||||
|
|
|
|
||||||
LL | let _ = TupleStruct {
|
LL | let _ = TupleStruct {
|
||||||
| _____________^
|
| _____________^
|
||||||
@ -21,13 +21,13 @@ LL | | 0: 1u32,
|
|||||||
LL | | 2: 2u8,
|
LL | | 2: 2u8,
|
||||||
LL | | 1: 3u32,
|
LL | | 1: 3u32,
|
||||||
LL | | };
|
LL | | };
|
||||||
| |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)`
|
| |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)`
|
||||||
|
|
||||||
error: used a field initializer for a tuple struct
|
error: used a field initializer for a tuple struct
|
||||||
--> tests/ui/numbered_fields.rs:49:13
|
--> tests/ui/init_numbered_fields.rs:49:13
|
||||||
|
|
|
|
||||||
LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
|
LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user