Skip to content

Commit c732f5a

Browse files
Allow formatting of use behind #[cfg*]
Fix #6666 We would like to allow formatting items with attributes that conceptually allows outer styling as well. Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
1 parent 01f2ec7 commit c732f5a

13 files changed

Lines changed: 168 additions & 17 deletions

src/imports.rs

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::borrow::Cow;
21
use std::cmp::Ordering;
32
use std::fmt;
3+
use std::{borrow::Cow, vec};
44

55
use core::hash::{Hash, Hasher};
66

@@ -130,7 +130,13 @@ pub(crate) struct UseTree {
130130

131131
impl PartialEq for UseTree {
132132
fn eq(&self, other: &UseTree) -> bool {
133+
// We bail out attributes because we cannot safely merge attributes.
134+
// We bail out comments because we cannot safely merge comments.
133135
self.path == other.path
136+
&& !self.has_attrs()
137+
&& !other.has_attrs()
138+
&& !self.has_comment()
139+
&& !other.has_comment()
134140
}
135141
}
136142
impl Eq for UseTree {}
@@ -233,13 +239,19 @@ pub(crate) fn normalize_use_trees_with_granularity(
233239

234240
let mut result = Vec::with_capacity(use_trees.len());
235241
for use_tree in use_trees {
236-
if use_tree.contains_comment() || use_tree.attrs.is_some() {
242+
if use_tree.contains_comment() || use_tree.has_attrs_disallow_outer_style() {
237243
result.push(use_tree);
238244
continue;
239245
}
246+
let attrs = use_tree.attrs.clone();
247+
let result_buf = if attrs.is_some() {
248+
&mut vec![]
249+
} else {
250+
&mut result
251+
};
240252

241253
for mut flattened in use_tree.flatten(import_granularity) {
242-
if let Some(tree) = result
254+
if let Some(tree) = result_buf
243255
.iter_mut()
244256
.find(|tree| tree.share_prefix(&flattened, merge_by))
245257
{
@@ -249,9 +261,19 @@ pub(crate) fn normalize_use_trees_with_granularity(
249261
if merge_by == SharedPrefix::Module {
250262
flattened = flattened.nest_trailing_self();
251263
}
252-
result.push(flattened);
264+
result_buf.push(flattened);
253265
}
254266
}
267+
if let Some(attrs) = attrs {
268+
let result_buf: Vec<_> = result_buf
269+
.drain(..)
270+
.map(|mut use_tree| {
271+
use_tree.attrs = Some(attrs.clone());
272+
use_tree
273+
})
274+
.collect();
275+
result.extend(result_buf);
276+
}
255277
}
256278
result
257279
}
@@ -386,11 +408,11 @@ impl UseTree {
386408
// use-statements. This should not be a problem, though, since we have
387409
// already tried to extract comment and observed that there are no comment
388410
// around the given use item, and the span will not be used afterward.
389-
fn from_path(path: Vec<UseSegment>, span: Span) -> UseTree {
411+
fn from_path(path: Vec<UseSegment>, span: Span, list_item: Option<ListItem>) -> UseTree {
390412
UseTree {
391413
path,
392414
span,
393-
list_item: None,
415+
list_item,
394416
visibility: None,
395417
attrs: None,
396418
}
@@ -559,7 +581,7 @@ impl UseTree {
559581

560582
// Remove foo::{} or self without attributes.
561583
match last.kind {
562-
_ if self.attrs.is_some() => (),
584+
_ if self.has_attrs() => (),
563585
UseSegmentKind::List(ref list) if list.is_empty() => {
564586
self.path = vec![];
565587
return self;
@@ -657,6 +679,17 @@ impl UseTree {
657679
self.has_comment() || self.path.iter().any(|path| path.contains_comment())
658680
}
659681

682+
fn has_attrs(&self) -> bool {
683+
self.attrs.is_some()
684+
}
685+
686+
fn has_attrs_disallow_outer_style(&self) -> bool {
687+
!self.attrs.iter().flatten().all(|attr| match &attr.kind {
688+
ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(),
689+
ast::AttrKind::DocComment(..) => false,
690+
})
691+
}
692+
660693
fn same_visibility(&self, other: &UseTree) -> bool {
661694
match (&self.visibility, &other.visibility) {
662695
(
@@ -682,7 +715,8 @@ impl UseTree {
682715
fn share_prefix(&self, other: &UseTree, shared_prefix: SharedPrefix) -> bool {
683716
if self.path.is_empty()
684717
|| other.path.is_empty()
685-
|| self.attrs.is_some()
718+
|| self.has_attrs()
719+
|| other.has_attrs()
686720
|| self.contains_comment()
687721
|| !self.same_visibility(other)
688722
{
@@ -696,8 +730,10 @@ impl UseTree {
696730
}
697731
}
698732

733+
/// The main tree-flattening process.
699734
fn flatten(self, import_granularity: ImportGranularity) -> Vec<UseTree> {
700-
if self.path.is_empty() || self.contains_comment() {
735+
if self.path.is_empty() || self.contains_comment() || self.has_attrs_disallow_outer_style()
736+
{
701737
return vec![self];
702738
}
703739
match &self.path.clone().last().unwrap().kind {
@@ -716,7 +752,7 @@ impl UseTree {
716752
result.push(UseTree {
717753
path: new_path,
718754
span: self.span,
719-
list_item: None,
755+
list_item: flattened.list_item.clone(),
720756
visibility: self.visibility.clone(),
721757
// only retain attributes for `ImportGranularity::Item`
722758
attrs: match import_granularity {
@@ -758,7 +794,11 @@ impl UseTree {
758794
{
759795
let self_segment = self.path.pop().unwrap();
760796
let style_edition = self_segment.style_edition;
761-
let kind = UseSegmentKind::List(vec![UseTree::from_path(vec![self_segment], DUMMY_SP)]);
797+
let kind = UseSegmentKind::List(vec![UseTree::from_path(
798+
vec![self_segment],
799+
DUMMY_SP,
800+
self.list_item.clone(),
801+
)]);
762802
self.path.push(UseSegment {
763803
kind,
764804
style_edition,
@@ -783,7 +823,7 @@ fn merge_rest(
783823
let mut list = list.clone();
784824
merge_use_trees_inner(
785825
&mut list,
786-
UseTree::from_path(b[len..].to_vec(), DUMMY_SP),
826+
UseTree::from_path(b[len..].to_vec(), DUMMY_SP, None),
787827
merge_by,
788828
);
789829
let mut new_path = b[..len].to_vec();
@@ -808,6 +848,7 @@ fn merge_rest(
808848
style_edition,
809849
}],
810850
DUMMY_SP,
851+
None,
811852
)];
812853
match rest {
813854
[
@@ -816,7 +857,7 @@ fn merge_rest(
816857
..
817858
},
818859
] => list.extend(rest_list.clone()),
819-
_ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
860+
_ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP, None)),
820861
}
821862
return Some(vec![
822863
b[0].clone(),
@@ -829,8 +870,8 @@ fn merge_rest(
829870
len -= 1;
830871
}
831872
let mut list = vec![
832-
UseTree::from_path(a[len..].to_vec(), DUMMY_SP),
833-
UseTree::from_path(b[len..].to_vec(), DUMMY_SP),
873+
UseTree::from_path(a[len..].to_vec(), DUMMY_SP, None),
874+
UseTree::from_path(b[len..].to_vec(), DUMMY_SP, None),
834875
];
835876
list.sort();
836877
list.dedup();

tests/source/imports/imports_granularity_crate.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,13 @@ use b::v::{
6363
};
6464
use b::t::{/* Before b::t::self */ self};
6565
use b::c;
66+
67+
// https://github.com/rust-lang/rustfmt/issues/6666
68+
#[cfg(true)]
69+
use a::{b::c, d::e, d::f};
70+
71+
#[my_attribute]
72+
use a::{b::c,d::e,d::f};
73+
74+
/// Some doc comment
75+
use a::{b::c,d::e,d::f};

tests/source/imports/imports_granularity_default-with-dups.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ use crate::lexer::{tokens::TokenData};
44
use crate::lexer::self;
55
use crate::lexer::{self};
66
use crate::lexer::{self, tokens::TokenData};
7+
8+
use a::{b::c, d::e, d::f};
9+
#[cfg(unix)]
10+
use a::{b::c, d::e, d::f};

tests/source/imports/imports_granularity_item-with-dups-StdExternalCrate-no-reorder.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ use crate::lexer;
1111
use crate::lexer;
1212
use crate::lexer::{self};
1313
use crate::lexer::{self, tokens::TokenData};
14+
15+
use crate::{b::c, d::e, d::f};
16+
#[cfg(unix)]
17+
use crate::{b::c, d::e, d::f};
18+
#[cfg(windows)]
19+
use crate::{b::c, d::e, d::f};
20+
// my comment
21+
use crate::b;

tests/source/imports/imports_granularity_item-with-dups.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ use crate::lexer;
99
use crate::lexer;
1010
use crate::lexer::{self};
1111
use crate::lexer::{self, tokens::TokenData};
12+
#[cfg(unix)]
13+
use crate::lexer;
14+
// FOO
15+
use crate::lexer;
16+
// BAR
17+
use crate::lexer;
18+
use crate::{lexer, /* lexer */ lexer};

tests/source/imports/imports_granularity_item.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,11 @@ use b::v::{
3232
};
3333
use b::t::{/* Before b::t::self */ self};
3434
use b::c;
35+
36+
use c::{a::b, c::d, c::e};
37+
#[cfg(unix)]
38+
use c::{a::b, c::d, c::e};
39+
#[cfg(windows)]
40+
use c::{a::b, c::d, c::e};
41+
// my comment
42+
use c::a::b;

tests/source/imports/imports_granularity_module.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,9 @@ use c;
5050
use d;
5151

5252
use {library1, library2 as lib2, library3};
53+
54+
#[my_attribute]
55+
use a::{b::c,d::e,d::f};
56+
57+
/// Some doc comment
58+
use a::{b::c,d::e,d::f};

tests/target/imports/imports_granularity_crate.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,16 @@ use b::{
5757
/* Before b::l group */ l::{self, m, n::o, p::*},
5858
q,
5959
};
60+
61+
// https://github.com/rust-lang/rustfmt/issues/6666
62+
#[cfg(true)]
63+
use a::{
64+
b::c,
65+
d::{e, f},
66+
};
67+
68+
#[my_attribute]
69+
use a::{b::c, d::e, d::f};
70+
71+
/// Some doc comment
72+
use a::{b::c, d::e, d::f};

tests/target/imports/imports_granularity_default-with-dups.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ use crate::lexer::tokens::TokenData;
44
use crate::lexer::tokens::TokenData;
55
use crate::lexer::{self};
66
use crate::lexer::{self, tokens::TokenData};
7+
8+
use a::{b::c, d::e, d::f};
9+
#[cfg(unix)]
10+
use a::{b::c, d::e, d::f};

tests/target/imports/imports_granularity_item-with-dups-StdExternalCrate-no-reorder.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,20 @@
55
use crate::lexer;
66
use crate::lexer::tokens::TokenData;
77
use crate::lexer::{self};
8+
use crate::b::c;
9+
use crate::d::e;
10+
use crate::d::f;
11+
#[cfg(unix)]
12+
use crate::b::c;
13+
#[cfg(unix)]
14+
use crate::d::e;
15+
#[cfg(unix)]
16+
use crate::d::f;
17+
#[cfg(windows)]
18+
use crate::b::c;
19+
#[cfg(windows)]
20+
use crate::d::e;
21+
#[cfg(windows)]
22+
use crate::d::f;
23+
// my comment
24+
use crate::b;

0 commit comments

Comments
 (0)