Skip to content

Commit 5327c36

Browse files
scampitopecongiro
authored andcommitted
handle field attributes when aligning a struct's fields (rust-lang#3513)
1 parent a5d16df commit 5327c36

File tree

5 files changed

+102
-25
lines changed

5 files changed

+102
-25
lines changed

src/items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1617,7 +1617,7 @@ pub(crate) fn rewrite_struct_field(
16171617
shape,
16181618
attrs_extendable,
16191619
)?;
1620-
let overhead = last_line_width(&attr_prefix);
1620+
let overhead = trimmed_last_line_width(&attr_prefix);
16211621
let lhs_offset = lhs_max_width.saturating_sub(overhead);
16221622
for _ in 0..lhs_offset {
16231623
spacing.push(' ');

src/vertical.rs

+14-19
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use itertools::Itertools;
66
use syntax::ast;
77
use syntax::source_map::{BytePos, Span};
88

9-
use crate::comment::{combine_strs_with_missing_comments, contains_comment};
9+
use crate::comment::combine_strs_with_missing_comments;
1010
use crate::config::lists::*;
1111
use crate::expr::rewrite_field;
1212
use crate::items::{rewrite_struct_field, rewrite_struct_field_prefix};
@@ -17,7 +17,9 @@ use crate::rewrite::{Rewrite, RewriteContext};
1717
use crate::shape::{Indent, Shape};
1818
use crate::source_map::SpanUtils;
1919
use crate::spanned::Spanned;
20-
use crate::utils::{contains_skip, is_attributes_extendable, mk_sp, rewrite_ident};
20+
use crate::utils::{
21+
contains_skip, is_attributes_extendable, mk_sp, rewrite_ident, trimmed_last_line_width,
22+
};
2123

2224
pub(crate) trait AlignedItem {
2325
fn skip(&self) -> bool;
@@ -183,13 +185,9 @@ fn struct_field_prefix_max_min_width<T: AlignedItem>(
183185
fields
184186
.iter()
185187
.map(|field| {
186-
field.rewrite_prefix(context, shape).and_then(|field_str| {
187-
if field_str.contains('\n') {
188-
None
189-
} else {
190-
Some(field_str.len())
191-
}
192-
})
188+
field
189+
.rewrite_prefix(context, shape)
190+
.map(|field_str| trimmed_last_line_width(&field_str))
193191
})
194192
.fold_options((0, ::std::usize::MAX), |(max_len, min_len), len| {
195193
(cmp::max(max_len, len), cmp::min(min_len, len))
@@ -255,6 +253,9 @@ fn rewrite_aligned_items_inner<T: AlignedItem>(
255253
write_list(&items, &fmt)
256254
}
257255

256+
/// Returns the index in `fields` up to which a field belongs to the current group.
257+
/// The returned string is the group separator to use when rewriting the fields.
258+
/// Groups are defined by blank lines.
258259
fn group_aligned_items<T: AlignedItem>(
259260
context: &RewriteContext<'_>,
260261
fields: &[T],
@@ -264,25 +265,19 @@ fn group_aligned_items<T: AlignedItem>(
264265
if fields[i].skip() {
265266
return ("", index);
266267
}
267-
// See if there are comments or empty lines between fields.
268268
let span = mk_sp(fields[i].get_span().hi(), fields[i + 1].get_span().lo());
269269
let snippet = context
270270
.snippet(span)
271271
.lines()
272272
.skip(1)
273273
.collect::<Vec<_>>()
274274
.join("\n");
275-
let spacings = if snippet
275+
let has_blank_line = snippet
276276
.lines()
277277
.dropping_back(1)
278-
.any(|l| l.trim().is_empty())
279-
{
280-
"\n"
281-
} else {
282-
""
283-
};
284-
if contains_comment(&snippet) || snippet.lines().count() > 1 {
285-
return (spacings, index);
278+
.any(|l| l.trim().is_empty());
279+
if has_blank_line {
280+
return ("\n", index);
286281
}
287282
index += 1;
288283
}

tests/source/issue-2869.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// rustfmt-struct_field_align_threshold: 50
2+
3+
#[derive(Serialize, Deserialize, Debug)]
4+
#[serde(rename_all = "PascalCase")]
5+
struct AuditLog1 {
6+
creation_time: String,
7+
id: String,
8+
operation: String,
9+
organization_id: String,
10+
record_type: u32,
11+
result_status: Option<String>,
12+
#[serde(rename = "ClientIP")]
13+
client_ip: Option<IpAddr>,
14+
object_id: String,
15+
actor: Option<Vec<IDType>>,
16+
actor_context_id: Option<String>,
17+
actor_ip_address: Option<IpAddr>,
18+
azure_active_directory_event_type: Option<u8>,
19+
20+
#[serde(rename = "very")]
21+
aaaaa: String,
22+
#[serde(rename = "cool")]
23+
bb: i32,
24+
}
25+
26+
#[derive(Serialize, Deserialize, Debug)]
27+
#[serde(rename_all = "PascalCase")]
28+
struct AuditLog2 {
29+
creation_time: String,
30+
id: String,
31+
operation: String,
32+
organization_id: String,
33+
record_type: u32,
34+
result_status: Option<String>,
35+
client_ip: Option<IpAddr>,
36+
object_id: String,
37+
actor: Option<Vec<IDType>>,
38+
actor_context_id: Option<String>,
39+
actor_ip_address: Option<IpAddr>,
40+
azure_active_directory_event_type: Option<u8>,
41+
}

tests/target/configs/struct_field_align_threshold/20.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ fn main() {
3838
pub struct Foo {
3939
#[rustfmt::skip]
4040
f : SomeType, // Comment beside a field
41-
f: SomeType, // Comment beside a field
41+
f: SomeType, // Comment beside a field
4242
// Comment on a field
4343
#[AnAttribute]
44-
g: SomeOtherType,
44+
g: SomeOtherType,
4545
/// A doc comment on a field
46-
h: AThirdType,
46+
h: AThirdType,
4747
pub i: TypeForPublicField,
4848
}
4949

@@ -66,7 +66,7 @@ struct X {
6666
pub struct Writebatch<K: Key> {
6767
#[allow(dead_code)] // only used for holding the internal pointer
6868
writebatch: RawWritebatch,
69-
marker: PhantomData<K>,
69+
marker: PhantomData<K>,
7070
}
7171

7272
struct Bar;
@@ -323,7 +323,7 @@ fn main() {
323323
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit
324324
// amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante
325325
// hendrerit. Donec et mollis dolor.
326-
first: item(),
326+
first: item(),
327327
// Praesent et diam eget libero egestas mattis sit amet vitae augue.
328328
// Nam tincidunt congue enim, ut porta lorem lacinia consectetur.
329329
second: Item,

tests/target/issue-2869.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// rustfmt-struct_field_align_threshold: 50
2+
3+
#[derive(Serialize, Deserialize, Debug)]
4+
#[serde(rename_all = "PascalCase")]
5+
struct AuditLog1 {
6+
creation_time: String,
7+
id: String,
8+
operation: String,
9+
organization_id: String,
10+
record_type: u32,
11+
result_status: Option<String>,
12+
#[serde(rename = "ClientIP")]
13+
client_ip: Option<IpAddr>,
14+
object_id: String,
15+
actor: Option<Vec<IDType>>,
16+
actor_context_id: Option<String>,
17+
actor_ip_address: Option<IpAddr>,
18+
azure_active_directory_event_type: Option<u8>,
19+
20+
#[serde(rename = "very")]
21+
aaaaa: String,
22+
#[serde(rename = "cool")]
23+
bb: i32,
24+
}
25+
26+
#[derive(Serialize, Deserialize, Debug)]
27+
#[serde(rename_all = "PascalCase")]
28+
struct AuditLog2 {
29+
creation_time: String,
30+
id: String,
31+
operation: String,
32+
organization_id: String,
33+
record_type: u32,
34+
result_status: Option<String>,
35+
client_ip: Option<IpAddr>,
36+
object_id: String,
37+
actor: Option<Vec<IDType>>,
38+
actor_context_id: Option<String>,
39+
actor_ip_address: Option<IpAddr>,
40+
azure_active_directory_event_type: Option<u8>,
41+
}

0 commit comments

Comments
 (0)