fix: handle synonymous imports in 'merge imports'

This commit is contained in:
roife 2024-07-18 04:57:29 +08:00
parent a62ea0a59e
commit 87a3ab4658
2 changed files with 82 additions and 5 deletions

View file

@ -164,6 +164,7 @@ impl Merge for ast::UseTree {
} }
} }
#[derive(Debug)]
enum Edit { enum Edit {
Remove(Either<ast::Use, ast::UseTree>), Remove(Either<ast::Use, ast::UseTree>),
Replace(SyntaxNode, SyntaxNode), Replace(SyntaxNode, SyntaxNode),
@ -733,4 +734,72 @@ use std::{
r"use std::fmt::{Debug, Display};", r"use std::fmt::{Debug, Display};",
); );
} }
#[test]
fn test_merge_with_synonymous_imports_1() {
check_assist(
merge_imports,
r"
mod top {
pub(crate) mod a {
pub(crate) struct A;
}
pub(crate) mod b {
pub(crate) struct B;
pub(crate) struct D;
}
}
use top::a::A;
use $0top::b::{B, B as C};
",
r"
mod top {
pub(crate) mod a {
pub(crate) struct A;
}
pub(crate) mod b {
pub(crate) struct B;
pub(crate) struct D;
}
}
use top::{a::A, b::{B, B as C}};
",
);
}
#[test]
fn test_merge_with_synonymous_imports_2() {
check_assist(
merge_imports,
r"
mod top {
pub(crate) mod a {
pub(crate) struct A;
}
pub(crate) mod b {
pub(crate) struct B;
pub(crate) struct D;
}
}
use top::a::A;
use $0top::b::{B as D, B as C};
",
r"
mod top {
pub(crate) mod a {
pub(crate) struct A;
}
pub(crate) mod b {
pub(crate) struct B;
pub(crate) struct D;
}
}
use top::{a::A, b::{B as D, B as C}};
",
);
}
} }

View file

@ -93,17 +93,25 @@ fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehav
let rhs_path = rhs.path()?; let rhs_path = rhs.path()?;
let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
if !(lhs.is_simple_path() if lhs.is_simple_path()
&& rhs.is_simple_path() && rhs.is_simple_path()
&& lhs_path == lhs_prefix && lhs_path == lhs_prefix
&& rhs_path == rhs_prefix) && rhs_path == rhs_prefix
{ {
lhs.split_prefix(&lhs_prefix); // we can't merge if the renames are different (`A as a` and `A as b`),
rhs.split_prefix(&rhs_prefix); // and we can safely return here
} else { let lhs_name = lhs.rename().and_then(|lhs_name| lhs_name.name());
let rhs_name = rhs.rename().and_then(|rhs_name| rhs_name.name());
if lhs_name != rhs_name {
return None;
}
ted::replace(lhs.syntax(), rhs.syntax()); ted::replace(lhs.syntax(), rhs.syntax());
// we can safely return here, in this case `recursive_merge` doesn't do anything // we can safely return here, in this case `recursive_merge` doesn't do anything
return Some(()); return Some(());
} else {
lhs.split_prefix(&lhs_prefix);
rhs.split_prefix(&rhs_prefix);
} }
} }
recursive_merge(lhs, rhs, merge) recursive_merge(lhs, rhs, merge)