fix: splitting path of a glob import wrongly adds self

`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).
This commit is contained in:
iDawer 2022-04-01 19:12:50 +05:00
parent bc08b8eff3
commit b4c608896c
4 changed files with 41 additions and 33 deletions

View File

@ -330,7 +330,7 @@ fn test_merge_nested_list_self_and_glob() {
use std::{fmt::{self, Display}}; use std::{fmt::{self, Display}};
", ",
r" r"
use std::{fmt::{self, *, Display}}; use std::{fmt::{*, self, Display}};
", ",
) )
} }
@ -440,4 +440,18 @@ fn test_empty_use() {
fn main() {}", 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( check_with_config(
"token::TokenKind", "token::TokenKind",
r"use token::TokenKind::*;", r"use token::TokenKind::*;",
r"use token::TokenKind::{self, *};", r"use token::TokenKind::{*, self};",
&InsertUseConfig { &InsertUseConfig {
granularity: ImportGranularity::Crate, granularity: ImportGranularity::Crate,
enforce_granularity: true, enforce_granularity: true,
@ -670,11 +670,10 @@ fn merge_mod_into_glob() {
#[test] #[test]
fn merge_self_glob() { fn merge_self_glob() {
cov_mark::check!(merge_self_glob);
check_with_config( check_with_config(
"self", "self",
r"use self::*;", r"use self::*;",
r"use self::{self, *};", r"use self::{*, self};",
&InsertUseConfig { &InsertUseConfig {
granularity: ImportGranularity::Crate, granularity: ImportGranularity::Crate,
enforce_granularity: true, enforce_granularity: true,
@ -693,7 +692,7 @@ fn merge_glob() {
r" r"
use syntax::{SyntaxKind::*};", use syntax::{SyntaxKind::*};",
r" r"
use syntax::{SyntaxKind::{self, *}};", use syntax::{SyntaxKind::{*, self}};",
) )
} }
@ -702,7 +701,7 @@ fn merge_glob_nested() {
check_crate( check_crate(
"foo::bar::quux::Fez", "foo::bar::quux::Fez",
r"use foo::bar::{Baz, quux::*};", 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 itertools::{EitherOrBoth, Itertools}; use itertools::{EitherOrBoth, Itertools};
use syntax::{ use syntax::{
ast::{self, make, AstNode, HasAttrs, HasVisibility, PathSegmentKind}, ast::{self, AstNode, HasAttrs, HasVisibility, PathSegmentKind},
ted, 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 if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() {
// 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() {
continue; continue;
} }
} }

View File

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