Skip to content

Commit 0671bf2

Browse files
committed
Fix MergingBehaviour::Last not working properly
1 parent 7c9ae77 commit 0671bf2

File tree

1 file changed

+52
-21
lines changed

1 file changed

+52
-21
lines changed

crates/assists/src/utils/insert_use.rs

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -174,28 +174,30 @@ pub(crate) fn try_merge_trees(
174174
let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
175175
let lhs = lhs.split_prefix(&lhs_prefix);
176176
let rhs = rhs.split_prefix(&rhs_prefix);
177-
recursive_merge(&lhs, &rhs, merge).map(|(merged, _)| merged)
177+
recursive_merge(&lhs, &rhs, merge)
178178
}
179179

180180
/// Recursively "zips" together lhs and rhs.
181181
fn recursive_merge(
182182
lhs: &ast::UseTree,
183183
rhs: &ast::UseTree,
184184
merge: MergeBehaviour,
185-
) -> Option<(ast::UseTree, bool)> {
185+
) -> Option<ast::UseTree> {
186186
let mut use_trees = lhs
187187
.use_tree_list()
188188
.into_iter()
189189
.flat_map(|list| list.use_trees())
190-
// check if any of the use trees are nested, if they are and the behaviour is `last` we are not allowed to merge this
191-
// so early exit the iterator by using Option's Intoiterator impl
192-
.map(|tree| match merge == MergeBehaviour::Last && tree.use_tree_list().is_some() {
193-
true => None,
194-
false => Some(tree),
190+
// we use Option here to early return from this function(this is not the same as a `filter` op)
191+
.map(|tree| match merge.is_tree_allowed(&tree) {
192+
true => Some(tree),
193+
false => None,
195194
})
196195
.collect::<Option<Vec<_>>>()?;
197196
use_trees.sort_unstable_by(|a, b| path_cmp_opt(a.path(), b.path()));
198197
for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) {
198+
if !merge.is_tree_allowed(&rhs_t) {
199+
return None;
200+
}
199201
let rhs_path = rhs_t.path();
200202
match use_trees.binary_search_by(|p| path_cmp_opt(p.path(), rhs_path.clone())) {
201203
Ok(idx) => {
@@ -239,17 +241,9 @@ fn recursive_merge(
239241
}
240242
let lhs = lhs_t.split_prefix(&lhs_prefix);
241243
let rhs = rhs_t.split_prefix(&rhs_prefix);
242-
let this_has_children = use_trees.len() > 0;
243244
match recursive_merge(&lhs, &rhs, merge) {
244-
Some((_, has_multiple_children))
245-
if merge == MergeBehaviour::Last
246-
&& this_has_children
247-
&& has_multiple_children =>
248-
{
249-
return None
250-
}
251-
Some((use_tree, _)) => use_trees[idx] = use_tree,
252-
None => use_trees.insert(idx, rhs_t),
245+
Some(use_tree) => use_trees[idx] = use_tree,
246+
None => return None,
253247
}
254248
}
255249
Err(_)
@@ -264,8 +258,7 @@ fn recursive_merge(
264258
}
265259
}
266260
}
267-
let has_multiple_children = use_trees.len() > 1;
268-
Some((lhs.with_use_tree_list(make::use_tree_list(use_trees)), has_multiple_children))
261+
Some(lhs.with_use_tree_list(make::use_tree_list(use_trees)))
269262
}
270263

271264
/// Traverses both paths until they differ, returning the common prefix of both.
@@ -308,6 +301,10 @@ fn segment_iter(path: &ast::Path) -> impl Iterator<Item = ast::PathSegment> + Cl
308301
successors(first_segment(path), |p| p.parent_path().parent_path().and_then(|p| p.segment()))
309302
}
310303

304+
fn path_len(path: ast::Path) -> usize {
305+
segment_iter(&path).count()
306+
}
307+
311308
/// Orders paths in the following way:
312309
/// the sole self token comes first, after that come uppercase identifiers, then lowercase identifiers
313310
// FIXME: rustfmt sort lowercase idents before uppercase, in general we want to have the same ordering rustfmt has
@@ -352,6 +349,19 @@ pub enum MergeBehaviour {
352349
Last,
353350
}
354351

352+
impl MergeBehaviour {
353+
#[inline]
354+
fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool {
355+
match self {
356+
MergeBehaviour::Full => true,
357+
// only simple single segment paths are allowed
358+
MergeBehaviour::Last => {
359+
tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1)
360+
}
361+
}
362+
}
363+
}
364+
355365
#[derive(Eq, PartialEq, PartialOrd, Ord)]
356366
enum ImportGroup {
357367
// the order here defines the order of new group inserts
@@ -675,6 +685,11 @@ use std::io;",
675685
)
676686
}
677687

688+
#[test]
689+
fn merge_last_into_self() {
690+
check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
691+
}
692+
678693
#[test]
679694
fn merge_groups_full() {
680695
check_full(
@@ -819,8 +834,24 @@ use std::io;",
819834
}
820835

821836
#[test]
822-
fn merge_last_too_long() {
823-
check_last("foo::bar", r"use foo::bar::baz::Qux;", r"use foo::bar::{self, baz::Qux};");
837+
fn skip_merge_last_too_long() {
838+
check_last(
839+
"foo::bar",
840+
r"use foo::bar::baz::Qux;",
841+
r"use foo::bar;
842+
use foo::bar::baz::Qux;",
843+
);
844+
}
845+
846+
#[test]
847+
#[ignore] // FIXME: Order changes when switching lhs and rhs
848+
fn skip_merge_last_too_long2() {
849+
check_last(
850+
"foo::bar::baz::Qux",
851+
r"use foo::bar;",
852+
r"use foo::bar;
853+
use foo::bar::baz::Qux;",
854+
);
824855
}
825856

826857
#[test]

0 commit comments

Comments
 (0)