Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_db/src/helpers/merge_imports.rs')
| -rw-r--r-- | crates/ide_db/src/helpers/merge_imports.rs | 95 |
1 files changed, 42 insertions, 53 deletions
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs index 6a7a9b8f61..8581a83436 100644 --- a/crates/ide_db/src/helpers/merge_imports.rs +++ b/crates/ide_db/src/helpers/merge_imports.rs @@ -44,10 +44,10 @@ pub fn try_merge_imports( } let lhs = lhs.clone_subtree().clone_for_update(); + let rhs = rhs.clone_subtree().clone_for_update(); let lhs_tree = lhs.use_tree()?; let rhs_tree = rhs.use_tree()?; - let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?; - ted::replace(lhs_tree.syntax(), merged.syntax()); + try_merge_trees_mut(&lhs_tree, &rhs_tree, merge_behavior)?; Some(lhs) } @@ -56,57 +56,49 @@ pub fn try_merge_trees( rhs: &ast::UseTree, merge: MergeBehavior, ) -> Option<ast::UseTree> { + let lhs = lhs.clone_subtree().clone_for_update(); + let rhs = rhs.clone_subtree().clone_for_update(); + try_merge_trees_mut(&lhs, &rhs, merge)?; + Some(lhs) +} + +fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { let lhs_path = lhs.path()?; let rhs_path = rhs.path()?; let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; - let (lhs, rhs) = if lhs.is_simple_path() + if !(lhs.is_simple_path() && rhs.is_simple_path() && lhs_path == lhs_prefix - && rhs_path == rhs_prefix + && rhs_path == rhs_prefix) { - (lhs.clone(), rhs.clone()) - } else { - (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix)) - }; - recursive_merge(&lhs, &rhs, merge).map(|it| it.clone_for_update()) + lhs.split_prefix(&lhs_prefix); + rhs.split_prefix(&rhs_prefix); + } + recursive_merge(&lhs, &rhs, merge) } -/// Recursively "zips" together lhs and rhs. -fn recursive_merge( - lhs: &ast::UseTree, - rhs: &ast::UseTree, - merge: MergeBehavior, -) -> Option<ast::UseTree> { - let mut use_trees = lhs +/// Recursively merges rhs to lhs +#[must_use] +fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> { + let mut use_trees: Vec<ast::UseTree> = lhs .use_tree_list() .into_iter() .flat_map(|list| list.use_trees()) // We use Option here to early return from this function(this is not the // same as a `filter` op). - .map(|tree| match merge.is_tree_allowed(&tree) { - true => Some(tree), - false => None, - }) - .collect::<Option<Vec<_>>>()?; + .map(|tree| merge.is_tree_allowed(&tree).then(|| tree)) + .collect::<Option<_>>()?; use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path())); for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) { if !merge.is_tree_allowed(&rhs_t) { return None; } let rhs_path = rhs_t.path(); - match use_trees.binary_search_by(|lhs_t| { - let (lhs_t, rhs_t) = match lhs_t - .path() - .zip(rhs_path.clone()) - .and_then(|(lhs, rhs)| common_prefix(&lhs, &rhs)) - { - Some((lhs_p, rhs_p)) => (lhs_t.split_prefix(&lhs_p), rhs_t.split_prefix(&rhs_p)), - None => (lhs_t.clone(), rhs_t.clone()), - }; - path_cmp_bin_search(lhs_t.path(), rhs_t.path()) - }) { + match use_trees + .binary_search_by(|lhs_t| path_cmp_bin_search(lhs_t.path(), rhs_path.as_ref())) + { Ok(idx) => { let lhs_t = &mut use_trees[idx]; let lhs_path = lhs_t.path()?; @@ -128,6 +120,7 @@ fn recursive_merge( match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) { (true, false) => continue, (false, true) => { + ted::replace(lhs_t.syntax(), rhs_t.syntax()); *lhs_t = rhs_t; continue; } @@ -142,25 +135,27 @@ fn recursive_merge( if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() { if tree_is_self(lhs_t) || tree_is_self(&rhs_t) { cov_mark::hit!(merge_self_glob); - *lhs_t = make::use_tree( + let self_tree = make::use_tree( make::path_unqualified(make::path_segment_self()), None, None, false, - ); - use_trees.insert(idx, make::use_tree_glob()); + ) + .clone_for_update(); + ted::replace(lhs_t.syntax(), self_tree.syntax()); + *lhs_t = self_tree; + let glob = make::use_tree_glob().clone_for_update(); + use_trees.insert(idx, glob.clone()); + lhs.get_or_create_use_tree_list().add_use_tree(glob); continue; } } else if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() { continue; } } - let lhs = lhs_t.split_prefix(&lhs_prefix); - let rhs = rhs_t.split_prefix(&rhs_prefix); - match recursive_merge(&lhs, &rhs, merge) { - Some(use_tree) => use_trees[idx] = use_tree, - None => return None, - } + lhs_t.split_prefix(&lhs_prefix); + rhs_t.split_prefix(&rhs_prefix); + recursive_merge(&lhs_t, &rhs_t, merge)?; } Err(_) if merge == MergeBehavior::Module @@ -170,16 +165,12 @@ fn recursive_merge( return None } Err(idx) => { - use_trees.insert(idx, rhs_t); + use_trees.insert(idx, rhs_t.clone()); + lhs.get_or_create_use_tree_list().add_use_tree(rhs_t); } } } - - let lhs = lhs.clone_subtree().clone_for_update(); - if let Some(old) = lhs.use_tree_list() { - ted::replace(old.syntax(), make::use_tree_list(use_trees).syntax().clone_for_update()); - } - ast::UseTree::cast(lhs.syntax().clone_subtree()) + Some(()) } /// Traverses both paths until they differ, returning the common prefix of both. @@ -224,11 +215,9 @@ fn path_cmp_for_sort(a: Option<ast::Path>, b: Option<ast::Path>) -> Ordering { } /// Path comparison func for binary searching for merging. -fn path_cmp_bin_search(lhs: Option<ast::Path>, rhs: Option<ast::Path>) -> Ordering { - match ( - lhs.as_ref().and_then(ast::Path::first_segment), - rhs.as_ref().and_then(ast::Path::first_segment), - ) { +fn path_cmp_bin_search(lhs: Option<ast::Path>, rhs: Option<&ast::Path>) -> Ordering { + match (lhs.as_ref().and_then(ast::Path::first_segment), rhs.and_then(ast::Path::first_segment)) + { (None, None) => Ordering::Equal, (None, Some(_)) => Ordering::Less, (Some(_), None) => Ordering::Greater, |