Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions crates/ide_assists/src/assist_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use ide_db::{
RootDatabase,
};
use syntax::{
algo::{self, find_node_at_offset, find_node_at_range, SyntaxRewriter},
algo::{self, find_node_at_offset, find_node_at_range},
AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
SyntaxToken, TextRange, TextSize, TokenAtOffset,
};
Expand Down Expand Up @@ -290,12 +290,6 @@ impl AssistBuilder {
pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
}
pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) {
if let Some(node) = rewriter.rewrite_root() {
let new = rewriter.rewrite(&node);
algo::diff(&node, &new).into_text_edit(&mut self.edit);
}
}
pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
let file_system_edit =
FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() };
Expand Down
90 changes: 33 additions & 57 deletions crates/ide_assists/src/handlers/expand_glob_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use ide_db::{
defs::{Definition, NameRefClass},
search::SearchScope,
};
use stdx::never;
use syntax::{
algo::SyntaxRewriter,
ast::{self, make},
AstNode, Direction, SyntaxNode, SyntaxToken, T,
ted, AstNode, Direction, SyntaxNode, SyntaxToken, T,
};

use crate::{
Expand Down Expand Up @@ -42,6 +42,7 @@ use crate::{
// ```
pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let star = ctx.find_token_syntax_at_offset(T![*])?;
let use_tree = star.parent().and_then(ast::UseTree::cast)?;
let (parent, mod_path) = find_parent_and_path(&star)?;
let target_module = match ctx.sema.resolve_path(&mod_path)? {
PathResolution::Def(ModuleDef::Module(it)) => it,
Expand All @@ -53,17 +54,39 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti

let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?;
let imported_defs = find_imported_defs(ctx, star)?;
let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);

let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone());
acc.add(
AssistId("expand_glob_import", AssistKind::RefactorRewrite),
"Expand glob import",
target.text_range(),
|builder| {
let mut rewriter = SyntaxRewriter::default();
replace_ast(&mut rewriter, parent, mod_path, names_to_import);
builder.rewrite(rewriter);
let use_tree = builder.make_ast_mut(use_tree);

let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
let path =
make::path_unqualified(make::path_segment(make::name_ref(&n.to_string())));
make::use_tree(path, None, None, false)
}))
.clone_for_update();

match use_tree.star_token() {
Some(star) => {
let needs_braces = use_tree.path().is_some() && names_to_import.len() > 1;
if needs_braces {
ted::replace(star, expanded.syntax())
} else {
let without_braces = expanded
.syntax()
.children_with_tokens()
.filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
.collect();
ted::replace_with_many(star, without_braces)
}
}
None => never!(),
}
},
)
}
Expand Down Expand Up @@ -232,53 +255,6 @@ fn find_names_to_import(
used_refs.0.iter().map(|r| r.visible_name.clone()).collect()
}

fn replace_ast(
rewriter: &mut SyntaxRewriter,
parent: Either<ast::UseTree, ast::UseTreeList>,
path: ast::Path,
names_to_import: Vec<Name>,
) {
let existing_use_trees = match parent.clone() {
Either::Left(_) => vec![],
Either::Right(u) => u
.use_trees()
.filter(|n|
// filter out star
n.star_token().is_none())
.collect(),
};

let new_use_trees: Vec<ast::UseTree> = names_to_import
.iter()
.map(|n| {
let path = make::path_unqualified(make::path_segment(make::name_ref(&n.to_string())));
make::use_tree(path, None, None, false)
})
.collect();

let use_trees = [&existing_use_trees[..], &new_use_trees[..]].concat();

match use_trees.as_slice() {
[name] => {
if let Some(end_path) = name.path() {
rewriter.replace_ast(
&parent.left_or_else(|tl| tl.parent_use_tree()),
&make::use_tree(make::path_concat(path, end_path), None, None, false),
);
}
}
names => match &parent {
Either::Left(parent) => rewriter.replace_ast(
parent,
&make::use_tree(path, Some(make::use_tree_list(names.to_owned())), None, false),
),
Either::Right(parent) => {
rewriter.replace_ast(parent, &make::use_tree_list(names.to_owned()))
}
},
};
}

#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
Expand Down Expand Up @@ -350,7 +326,7 @@ mod foo {
pub fn f() {}
}

use foo::{f, Baz, Bar};
use foo::{Baz, Bar, f};

fn qux(bar: Bar, baz: Baz) {
f();
Expand Down Expand Up @@ -389,7 +365,7 @@ mod foo {
}

use foo::Bar;
use foo::{f, Baz};
use foo::{Baz, f};

fn qux(bar: Bar, baz: Baz) {
f();
Expand Down Expand Up @@ -439,7 +415,7 @@ mod foo {
}
}

use foo::{bar::{f, Baz, Bar}, baz::*};
use foo::{bar::{Baz, Bar, f}, baz::*};

fn qux(bar: Bar, baz: Baz) {
f();
Expand Down Expand Up @@ -891,7 +867,7 @@ mod foo {
pub struct Bar;
}

use foo::Bar;
use foo::{Bar};

struct Baz {
bar: Bar
Expand Down
5 changes: 4 additions & 1 deletion crates/syntax/src/ted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,11 @@ pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) {
}

pub fn replace(old: impl Element, new: impl Element) {
replace_with_many(old, vec![new.syntax_element()])
}
pub fn replace_with_many(old: impl Element, new: Vec<SyntaxElement>) {
let old = old.syntax_element();
replace_all(old.clone()..=old, vec![new.syntax_element()])
replace_all(old.clone()..=old, new)
}
pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
let start = range.start().index();
Expand Down