Skip to content

Commit 28c08e4

Browse files
committed
Share code with merge_use_trees
1 parent 442615a commit 28c08e4

File tree

2 files changed

+89
-73
lines changed

2 files changed

+89
-73
lines changed

src/formatting/imports.rs

+82-70
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ impl UseSegment {
160160
}
161161
}
162162

163-
pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>) -> Vec<UseTree> {
163+
pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>, merge_by: SharedPrefix) -> Vec<UseTree> {
164164
let mut result = Vec::with_capacity(use_trees.len());
165165
for use_tree in use_trees {
166166
if use_tree.has_comment() || use_tree.attrs.is_some() {
@@ -169,8 +169,11 @@ pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>) -> Vec<UseTree> {
169169
}
170170

171171
for flattened in use_tree.flatten() {
172-
if let Some(tree) = result.iter_mut().find(|tree| tree.share_prefix(&flattened)) {
173-
tree.merge(&flattened);
172+
if let Some(tree) = result
173+
.iter_mut()
174+
.find(|tree| tree.share_prefix(&flattened, merge_by))
175+
{
176+
tree.merge(&flattened, merge_by);
174177
} else {
175178
result.push(flattened);
176179
}
@@ -179,48 +182,6 @@ pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>) -> Vec<UseTree> {
179182
result
180183
}
181184

182-
/// Split apart nested imports in use trees.
183-
pub(crate) fn unnest_use_trees(mut use_trees: Vec<UseTree>) -> Vec<UseTree> {
184-
let mut result = Vec::with_capacity(use_trees.len());
185-
while let Some(mut use_tree) = use_trees.pop() {
186-
if !use_tree.has_comment() && use_tree.attrs.is_none() {
187-
if let Some((UseSegment::List(list), ref prefix)) = use_tree.path.split_last_mut() {
188-
let span = use_tree.span;
189-
let visibility = &use_tree.visibility;
190-
list.retain(|nested_use_tree| {
191-
if matches!(
192-
nested_use_tree.path[..],
193-
[UseSegment::Ident(..)] | [UseSegment::Slf(..)] | [UseSegment::Glob]
194-
) {
195-
return true;
196-
}
197-
if nested_use_tree.has_comment() {
198-
return true;
199-
}
200-
// nested item detected; flatten once, but process it again
201-
// in case it has more nesting
202-
use_trees.push(UseTree {
203-
path: prefix
204-
.iter()
205-
.cloned()
206-
.chain(nested_use_tree.path.iter().cloned())
207-
.collect(),
208-
span,
209-
list_item: None,
210-
visibility: visibility.clone(),
211-
attrs: None,
212-
});
213-
// remove this item
214-
false
215-
});
216-
use_tree = use_tree.normalize();
217-
}
218-
}
219-
result.push(use_tree);
220-
}
221-
result
222-
}
223-
224185
impl fmt::Debug for UseTree {
225186
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226187
fmt::Display::fmt(self, f)
@@ -568,15 +529,20 @@ impl UseTree {
568529
}
569530
}
570531

571-
fn share_prefix(&self, other: &UseTree) -> bool {
532+
fn share_prefix(&self, other: &UseTree, shared_prefix: SharedPrefix) -> bool {
572533
if self.path.is_empty()
573534
|| other.path.is_empty()
574535
|| self.attrs.is_some()
575536
|| !self.same_visibility(other)
576537
{
577538
false
578539
} else {
579-
self.path[0] == other.path[0]
540+
match shared_prefix {
541+
SharedPrefix::Crate => self.path[0] == other.path[0],
542+
SharedPrefix::Module => {
543+
self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1]
544+
}
545+
}
580546
}
581547
}
582548

@@ -610,7 +576,7 @@ impl UseTree {
610576
}
611577
}
612578

613-
fn merge(&mut self, other: &UseTree) {
579+
fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) {
614580
let mut prefix = 0;
615581
for (a, b) in self.path.iter().zip(other.path.iter()) {
616582
if *a == *b {
@@ -619,20 +585,30 @@ impl UseTree {
619585
break;
620586
}
621587
}
622-
if let Some(new_path) = merge_rest(&self.path, &other.path, prefix) {
588+
if let Some(new_path) = merge_rest(&self.path, &other.path, prefix, merge_by) {
623589
self.path = new_path;
624590
self.span = self.span.to(other.span);
625591
}
626592
}
627593
}
628594

629-
fn merge_rest(a: &[UseSegment], b: &[UseSegment], mut len: usize) -> Option<Vec<UseSegment>> {
595+
fn merge_rest(
596+
a: &[UseSegment],
597+
b: &[UseSegment],
598+
mut len: usize,
599+
merge_by: SharedPrefix,
600+
) -> Option<Vec<UseSegment>> {
630601
if a.len() == len && b.len() == len {
631602
return None;
632603
}
633604
if a.len() != len && b.len() != len {
634-
if let UseSegment::List(mut list) = a[len].clone() {
635-
merge_use_trees_inner(&mut list, UseTree::from_path(b[len..].to_vec(), DUMMY_SP));
605+
if let UseSegment::List(ref list) = a[len] {
606+
let mut list = list.clone();
607+
merge_use_trees_inner(
608+
&mut list,
609+
UseTree::from_path(b[len..].to_vec(), DUMMY_SP),
610+
merge_by,
611+
);
636612
let mut new_path = b[..len].to_vec();
637613
new_path.push(UseSegment::List(list));
638614
return Some(new_path);
@@ -659,17 +635,19 @@ fn merge_rest(a: &[UseSegment], b: &[UseSegment], mut len: usize) -> Option<Vec<
659635
Some(new_path)
660636
}
661637

662-
fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree) {
663-
let similar_trees = trees.iter_mut().filter(|tree| tree.share_prefix(&use_tree));
664-
if use_tree.path.len() == 1 {
638+
fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
639+
let similar_trees = trees
640+
.iter_mut()
641+
.filter(|tree| tree.share_prefix(&use_tree, merge_by));
642+
if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate {
665643
if let Some(tree) = similar_trees.min_by_key(|tree| tree.path.len()) {
666644
if tree.path.len() == 1 {
667645
return;
668646
}
669647
}
670648
} else if let Some(tree) = similar_trees.max_by_key(|tree| tree.path.len()) {
671649
if tree.path.len() > 1 {
672-
tree.merge(&use_tree);
650+
tree.merge(&use_tree, merge_by);
673651
return;
674652
}
675653
}
@@ -872,6 +850,12 @@ impl Rewrite for UseTree {
872850
}
873851
}
874852

853+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
854+
pub(crate) enum SharedPrefix {
855+
Crate,
856+
Module,
857+
}
858+
875859
#[cfg(test)]
876860
mod test {
877861
use super::*;
@@ -1018,44 +1002,72 @@ mod test {
10181002
}
10191003
}
10201004

1021-
#[test]
1022-
fn test_use_tree_merge() {
1023-
macro_rules! test_merge {
1024-
([$($input:expr),* $(,)*], [$($output:expr),* $(,)*]) => {
1025-
assert_eq!(
1026-
merge_use_trees(parse_use_trees!($($input,)*)),
1027-
parse_use_trees!($($output,)*),
1028-
);
1029-
}
1005+
macro_rules! test_merge {
1006+
($by:ident, [$($input:expr),* $(,)*], [$($output:expr),* $(,)*]) => {
1007+
assert_eq!(
1008+
merge_use_trees(parse_use_trees!($($input,)*), SharedPrefix::$by),
1009+
parse_use_trees!($($output,)*),
1010+
);
10301011
}
1012+
}
10311013

1032-
test_merge!(["a::b::{c, d}", "a::b::{e, f}"], ["a::b::{c, d, e, f}"]);
1033-
test_merge!(["a::b::c", "a::b"], ["a::{b, b::c}"]);
1034-
test_merge!(["a::b", "a::b"], ["a::b"]);
1035-
test_merge!(["a", "a::b", "a::b::c"], ["a::{self, b, b::c}"]);
1014+
#[test]
1015+
fn test_use_tree_merge_crate() {
1016+
test_merge!(
1017+
Crate,
1018+
["a::b::{c, d}", "a::b::{e, f}"],
1019+
["a::b::{c, d, e, f}"]
1020+
);
1021+
test_merge!(Crate, ["a::b::c", "a::b"], ["a::{b, b::c}"]);
1022+
test_merge!(Crate, ["a::b", "a::b"], ["a::b"]);
1023+
test_merge!(Crate, ["a", "a::b", "a::b::c"], ["a::{self, b, b::c}"]);
10361024
test_merge!(
1025+
Crate,
10371026
["a", "a::b", "a::b::c", "a::b::c::d"],
10381027
["a::{self, b, b::{c, c::d}}"]
10391028
);
1040-
test_merge!(["a", "a::b", "a::b::c", "a::b"], ["a::{self, b, b::c}"]);
10411029
test_merge!(
1030+
Crate,
1031+
["a", "a::b", "a::b::c", "a::b"],
1032+
["a::{self, b, b::c}"]
1033+
);
1034+
test_merge!(
1035+
Crate,
10421036
["a::{b::{self, c}, d::e}", "a::d::f"],
10431037
["a::{b::{self, c}, d::{e, f}}"]
10441038
);
10451039
test_merge!(
1040+
Crate,
10461041
["a::d::f", "a::{b::{self, c}, d::e}"],
10471042
["a::{b::{self, c}, d::{e, f}}"]
10481043
);
10491044
test_merge!(
1045+
Crate,
10501046
["a::{c, d, b}", "a::{d, e, b, a, f}", "a::{f, g, c}"],
10511047
["a::{a, b, c, d, e, f, g}"]
10521048
);
10531049
test_merge!(
1050+
Crate,
10541051
["a::{self}", "b::{self as foo}"],
10551052
["a::{self}", "b::{self as foo}"]
10561053
);
10571054
}
10581055

1056+
#[test]
1057+
fn test_use_tree_merge_module() {
1058+
test_merge!(
1059+
Module,
1060+
["foo::b", "foo::{a, c, d::e}"],
1061+
["foo::{a, b, c}", "foo::d::e"]
1062+
);
1063+
1064+
test_merge!(
1065+
Module,
1066+
["foo::{a::b, a::c, d::e, d::f}"],
1067+
["foo::a::{b, c}", "foo::d::{e, f}"]
1068+
);
1069+
}
1070+
10591071
#[test]
10601072
fn test_use_tree_flatten() {
10611073
assert_eq!(

src/formatting/reorder.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::config::{Config, GroupImportsTactic, ImportMergeStyle};
1515
use crate::formatting::imports::UseSegment;
1616
use crate::formatting::modules::{get_mod_inner_attrs, FileModMap};
1717
use crate::formatting::{
18-
imports::{merge_use_trees, unnest_use_trees, UseTree},
18+
imports::{merge_use_trees, UseTree},
1919
items::{is_mod_decl, rewrite_extern_crate, rewrite_mod},
2020
lists::{itemize_list, write_list, ListFormatting, ListItem},
2121
rewrite::RewriteContext,
@@ -26,6 +26,8 @@ use crate::formatting::{
2626
visitor::FmtVisitor,
2727
};
2828

29+
use super::imports::SharedPrefix;
30+
2931
/// Compare strings according to version sort (roughly equivalent to `strverscmp`)
3032
pub(crate) fn compare_as_versions(left: &str, right: &str) -> Ordering {
3133
let mut left = left.chars().peekable();
@@ -227,9 +229,11 @@ fn rewrite_reorderable_or_regroupable_items(
227229
item.list_item = Some(list_item.clone());
228230
}
229231
match context.config.imports_merge_style() {
230-
ImportMergeStyle::Crate => normalized_items = merge_use_trees(normalized_items),
232+
ImportMergeStyle::Crate => {
233+
normalized_items = merge_use_trees(normalized_items, SharedPrefix::Crate)
234+
}
231235
ImportMergeStyle::Module => {
232-
normalized_items = unnest_use_trees(merge_use_trees(normalized_items))
236+
normalized_items = merge_use_trees(normalized_items, SharedPrefix::Module)
233237
}
234238
ImportMergeStyle::Preserve => {}
235239
}

0 commit comments

Comments
 (0)