Skip to content

Commit 29c1dbd

Browse files
committed
Address all review comments but one
This comment is not yet addressed: #13737 (comment)
1 parent 57fb2f1 commit 29c1dbd

File tree

6 files changed

+143
-21
lines changed

6 files changed

+143
-21
lines changed

book/src/lint_configuration.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,9 @@ A list of paths to types that should be treated as if they do not contain interi
565565
## `initializer-suggestions`
566566
Whether to suggest reordering constructor fields when initializers are present.
567567

568-
Note that such suggestions are not applied automatically with `--fix`. The following example
569-
[due to @ronnodas] shows why. Swapping the fields in the constructor produces incompilable code:
568+
Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
569+
suggested code would compile, it can change semantics if the initializer expressions have side effects. The
570+
following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
570571

571572
```rust
572573
struct MyStruct {
@@ -579,7 +580,7 @@ fn main() {
579580
}
580581
```
581582

582-
[due to @ronnodas]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
583+
[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
583584

584585
**Default Value:** `false`
585586

clippy_config/src/conf.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,9 @@ define_Conf! {
528528
ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]),
529529
/// Whether to suggest reordering constructor fields when initializers are present.
530530
///
531-
/// Note that such suggestions are not applied automatically with `--fix`. The following example
532-
/// [due to @ronnodas] shows why. Swapping the fields in the constructor produces incompilable code:
531+
/// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
532+
/// suggested code would compile, it can change semantics if the initializer expressions have side effects. The
533+
/// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
533534
///
534535
/// ```rust
535536
/// struct MyStruct {
@@ -542,7 +543,7 @@ define_Conf! {
542543
/// }
543544
/// ```
544545
///
545-
/// [due to @ronnodas]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
546+
/// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
546547
#[lints(inconsistent_struct_constructor)]
547548
initializer_suggestions: bool = false,
548549
/// The maximum size of the `Err`-variant in a `Result` returned from a function

clippy_lints/src/inconsistent_struct_constructor.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_config::Conf;
2-
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::fulfill_or_allowed;
4-
use clippy_utils::source::snippet_opt;
4+
use clippy_utils::source::snippet;
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_errors::Applicability;
77
use rustc_hir::{self as hir, ExprKind};
@@ -83,7 +83,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
8383
let ExprKind::Struct(_, fields, _) = expr.kind else {
8484
return;
8585
};
86-
let applicability = if fields.iter().all(|f| f.is_shorthand) {
86+
let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand);
87+
let applicability = if all_fields_are_shorthand {
8788
Applicability::MachineApplicable
8889
} else if self.initializer_suggestions {
8990
Applicability::MaybeIncorrect
@@ -109,17 +110,22 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
109110

110111
let span = field_with_attrs_span(cx.tcx, fields.first().unwrap())
111112
.with_hi(field_with_attrs_span(cx.tcx, fields.last().unwrap()).hi());
112-
let sugg = suggestion(cx, fields, &def_order_map);
113113

114114
if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) {
115-
span_lint_and_sugg(
115+
span_lint_and_then(
116116
cx,
117117
INCONSISTENT_STRUCT_CONSTRUCTOR,
118118
span,
119119
"struct constructor field order is inconsistent with struct definition field order",
120-
"try",
121-
sugg,
122-
applicability,
120+
|diag| {
121+
let msg = if all_fields_are_shorthand {
122+
"try"
123+
} else {
124+
"if the field evaluation order doesn't matter, try"
125+
};
126+
let sugg = suggestion(cx, fields, &def_order_map);
127+
diag.span_suggestion(span, msg, sugg, applicability);
128+
},
123129
);
124130
}
125131
}
@@ -151,16 +157,16 @@ fn suggestion<'tcx>(
151157
.map(|w| {
152158
let w0_span = field_with_attrs_span(cx.tcx, &w[0]);
153159
let w1_span = field_with_attrs_span(cx.tcx, &w[1]);
154-
let span = w0_span.with_hi(w1_span.lo()).with_lo(w0_span.hi());
155-
snippet_opt(cx, span).unwrap()
160+
let span = w0_span.between(w1_span);
161+
snippet(cx, span, " ")
156162
})
157163
.collect::<Vec<_>>();
158164

159165
let mut fields = fields.to_vec();
160166
fields.sort_unstable_by_key(|field| def_order_map[&field.ident.name]);
161167
let field_snippets = fields
162168
.iter()
163-
.map(|field| snippet_opt(cx, field_with_attrs_span(cx.tcx, field)).unwrap())
169+
.map(|field| snippet(cx, field_with_attrs_span(cx.tcx, field), ".."))
164170
.collect::<Vec<_>>();
165171

166172
assert_eq!(field_snippets.len(), ws.len() + 1);

tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,41 @@ mod field_attributes {
3939
};
4040
}
4141
}
42+
43+
// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
44+
mod cfgs_between_fields {
45+
#[allow(clippy::non_minimal_cfg)]
46+
fn cfg_all() {
47+
struct S {
48+
a: i32,
49+
b: i32,
50+
#[cfg(all())]
51+
c: i32,
52+
d: i32,
53+
}
54+
let s = S {
55+
a: 3,
56+
b: 2,
57+
#[cfg(all())]
58+
c: 1,
59+
d: 0,
60+
};
61+
}
62+
63+
fn cfg_any() {
64+
struct S {
65+
a: i32,
66+
b: i32,
67+
#[cfg(any())]
68+
c: i32,
69+
d: i32,
70+
}
71+
let s = S {
72+
a: 3,
73+
#[cfg(any())]
74+
c: 1,
75+
b: 2,
76+
d: 0,
77+
};
78+
}
79+
}

tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,41 @@ mod field_attributes {
3939
};
4040
}
4141
}
42+
43+
// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
44+
mod cfgs_between_fields {
45+
#[allow(clippy::non_minimal_cfg)]
46+
fn cfg_all() {
47+
struct S {
48+
a: i32,
49+
b: i32,
50+
#[cfg(all())]
51+
c: i32,
52+
d: i32,
53+
}
54+
let s = S {
55+
d: 0,
56+
#[cfg(all())]
57+
c: 1,
58+
b: 2,
59+
a: 3,
60+
};
61+
}
62+
63+
fn cfg_any() {
64+
struct S {
65+
a: i32,
66+
b: i32,
67+
#[cfg(any())]
68+
c: i32,
69+
d: i32,
70+
}
71+
let s = S {
72+
d: 0,
73+
#[cfg(any())]
74+
c: 1,
75+
b: 2,
76+
a: 3,
77+
};
78+
}
79+
}

tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: struct constructor field order is inconsistent with struct definition fie
22
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:18:11
33
|
44
LL | Foo { y, x, z: z };
5-
| ^^^^^^^^^^ help: try: `x, y, z: z`
5+
| ^^^^^^^^^^ help: if the field evaluation order doesn't matter, try: `x, y, z: z`
66
|
77
= note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]`
@@ -14,7 +14,7 @@ LL | / z: z,
1414
LL | | x,
1515
| |_________^
1616
|
17-
help: try
17+
help: if the field evaluation order doesn't matter, try
1818
|
1919
LL ~ x,
2020
LL ~ z: z,
@@ -28,12 +28,50 @@ LL | | expn_depth: if condition { 1 } else { 0 },
2828
LL | | macro_unsafe_blocks: Vec::new(),
2929
| |___________________________________________^
3030
|
31-
help: try
31+
help: if the field evaluation order doesn't matter, try
3232
|
3333
LL ~ macro_unsafe_blocks: Vec::new(),
3434
LL + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
3535
LL ~ expn_depth: if condition { 1 } else { 0 },
3636
|
3737

38-
error: aborting due to 3 previous errors
38+
error: struct constructor field order is inconsistent with struct definition field order
39+
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:55:13
40+
|
41+
LL | / d: 0,
42+
LL | | #[cfg(all())]
43+
LL | | c: 1,
44+
LL | | b: 2,
45+
LL | | a: 3,
46+
| |________________^
47+
|
48+
help: if the field evaluation order doesn't matter, try
49+
|
50+
LL ~ a: 3,
51+
LL + b: 2,
52+
LL + #[cfg(all())]
53+
LL + c: 1,
54+
LL ~ d: 0,
55+
|
56+
57+
error: struct constructor field order is inconsistent with struct definition field order
58+
--> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:72:13
59+
|
60+
LL | / d: 0,
61+
LL | | #[cfg(any())]
62+
LL | | c: 1,
63+
LL | | b: 2,
64+
LL | | a: 3,
65+
| |________________^
66+
|
67+
help: if the field evaluation order doesn't matter, try
68+
|
69+
LL ~ a: 3,
70+
LL + #[cfg(any())]
71+
LL + c: 1,
72+
LL + b: 2,
73+
LL ~ d: 0,
74+
|
75+
76+
error: aborting due to 5 previous errors
3977

0 commit comments

Comments
 (0)