11877: fix: splitting path of a glob import wrongly adds `self` r=Veykril a=iDawer

Close  #11703 

`ast::UseTree::split_prefix` handles globs now.
Removed an extra branch for globs in `ide_db::imports::merge_imports::recursive_merge` (superseeded by split_prefix).

Co-authored-by: iDawer <ilnur.iskhakov.oss@outlook.com>
This commit is contained in:
bors[bot] 2022-04-02 22:12:59 +00:00 committed by GitHub
commit ba9aed19c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 33 deletions

View file

@ -330,7 +330,7 @@ use std$0::{fmt::*};
use std::{fmt::{self, Display}};
",
r"
use std::{fmt::{self, *, Display}};
use std::{fmt::{*, self, Display}};
",
)
}
@ -440,4 +440,18 @@ use std::$0
fn main() {}",
);
}
#[test]
fn split_glob() {
check_assist(
merge_imports,
r"
use foo::$0*;
use foo::bar::Baz;
",
r"
use foo::{*, bar::Baz};
",
);
}
}

View file

@ -656,7 +656,7 @@ fn merge_mod_into_glob() {
check_with_config(
"token::TokenKind",
r"use token::TokenKind::*;",
r"use token::TokenKind::{self, *};",
r"use token::TokenKind::{*, self};",
&InsertUseConfig {
granularity: ImportGranularity::Crate,
enforce_granularity: true,
@ -670,11 +670,10 @@ fn merge_mod_into_glob() {
#[test]
fn merge_self_glob() {
cov_mark::check!(merge_self_glob);
check_with_config(
"self",
r"use self::*;",
r"use self::{self, *};",
r"use self::{*, self};",
&InsertUseConfig {
granularity: ImportGranularity::Crate,
enforce_granularity: true,
@ -693,7 +692,7 @@ fn merge_glob() {
r"
use syntax::{SyntaxKind::*};",
r"
use syntax::{SyntaxKind::{self, *}};",
use syntax::{SyntaxKind::{*, self}};",
)
}
@ -702,7 +701,7 @@ fn merge_glob_nested() {
check_crate(
"foo::bar::quux::Fez",
r"use foo::bar::{Baz, quux::*};",
r"use foo::bar::{Baz, quux::{self::*, Fez}};",
r"use foo::bar::{Baz, quux::{*, Fez}};",
)
}

View file

@ -3,7 +3,7 @@ use std::cmp::Ordering;
use itertools::{EitherOrBoth, Itertools};
use syntax::{
ast::{self, make, AstNode, HasAttrs, HasVisibility, PathSegmentKind},
ast::{self, AstNode, HasAttrs, HasVisibility, PathSegmentKind},
ted,
};
@ -129,29 +129,7 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior)
_ => (),
}
// Glob imports aren't part of the use-tree lists so we need
// to special handle them here as well this special handling
// is only required for when we merge a module import into a
// glob import of said module see the `merge_self_glob` or
// `merge_mod_into_glob` tests.
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);
let self_tree = make::use_tree(
make::path_unqualified(make::path_segment_self()),
None,
None,
false,
)
.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() {
if lhs_t.is_simple_path() && rhs_t.is_simple_path() {
continue;
}
}

View file

@ -302,16 +302,33 @@ impl ast::UseTree {
/// Splits off the given prefix, making it the path component of the use tree,
/// appending the rest of the path to all UseTreeList items.
///
/// # Examples
///
/// `prefix$0::suffix` -> `prefix::{suffix}`
///
/// `prefix$0` -> `prefix::{self}`
///
/// `prefix$0::*` -> `prefix::{*}`
pub fn split_prefix(&self, prefix: &ast::Path) {
debug_assert_eq!(self.path(), Some(prefix.top_path()));
let path = self.path().unwrap();
if &path == prefix && self.use_tree_list().is_none() {
let self_suffix = make::path_unqualified(make::path_segment_self()).clone_for_update();
ted::replace(path.syntax(), self_suffix.syntax());
if self.star_token().is_some() {
// path$0::* -> *
self.coloncolon_token().map(ted::remove);
ted::remove(prefix.syntax());
} else {
// path$0 -> self
let self_suffix =
make::path_unqualified(make::path_segment_self()).clone_for_update();
ted::replace(path.syntax(), self_suffix.syntax());
}
} else if split_path_prefix(prefix).is_none() {
return;
}
// At this point, prefix path is detached; _self_ use tree has suffix path.
// Next, transform 'suffix' use tree into 'prefix::{suffix}'
let subtree = self.clone_subtree().clone_for_update();
ted::remove_all_iter(self.syntax().children_with_tokens());
ted::insert(Position::first_child_of(self.syntax()), prefix.syntax());