aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r--crates/ide_assists/src/assist_context.rs8
-rw-r--r--crates/ide_assists/src/handlers/expand_glob_import.rs90
2 files changed, 34 insertions, 64 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs
index 112939948..682f0ff5e 100644
--- a/crates/ide_assists/src/assist_context.rs
+++ b/crates/ide_assists/src/assist_context.rs
@@ -13,7 +13,7 @@ use ide_db::{
13 RootDatabase, 13 RootDatabase,
14}; 14};
15use syntax::{ 15use syntax::{
16 algo::{self, find_node_at_offset, find_node_at_range, SyntaxRewriter}, 16 algo::{self, find_node_at_offset, find_node_at_range},
17 AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, 17 AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
18 SyntaxToken, TextRange, TextSize, TokenAtOffset, 18 SyntaxToken, TextRange, TextSize, TokenAtOffset,
19}; 19};
@@ -290,12 +290,6 @@ impl AssistBuilder {
290 pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { 290 pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
291 algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) 291 algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
292 } 292 }
293 pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) {
294 if let Some(node) = rewriter.rewrite_root() {
295 let new = rewriter.rewrite(&node);
296 algo::diff(&node, &new).into_text_edit(&mut self.edit);
297 }
298 }
299 pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { 293 pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
300 let file_system_edit = 294 let file_system_edit =
301 FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() }; 295 FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() };
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs
index 98389e4f7..e3095f26b 100644
--- a/crates/ide_assists/src/handlers/expand_glob_import.rs
+++ b/crates/ide_assists/src/handlers/expand_glob_import.rs
@@ -4,10 +4,10 @@ use ide_db::{
4 defs::{Definition, NameRefClass}, 4 defs::{Definition, NameRefClass},
5 search::SearchScope, 5 search::SearchScope,
6}; 6};
7use stdx::never;
7use syntax::{ 8use syntax::{
8 algo::SyntaxRewriter,
9 ast::{self, make}, 9 ast::{self, make},
10 AstNode, Direction, SyntaxNode, SyntaxToken, T, 10 ted, AstNode, Direction, SyntaxNode, SyntaxToken, T,
11}; 11};
12 12
13use crate::{ 13use crate::{
@@ -42,6 +42,7 @@ use crate::{
42// ``` 42// ```
43pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 43pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
44 let star = ctx.find_token_syntax_at_offset(T![*])?; 44 let star = ctx.find_token_syntax_at_offset(T![*])?;
45 let use_tree = star.parent().and_then(ast::UseTree::cast)?;
45 let (parent, mod_path) = find_parent_and_path(&star)?; 46 let (parent, mod_path) = find_parent_and_path(&star)?;
46 let target_module = match ctx.sema.resolve_path(&mod_path)? { 47 let target_module = match ctx.sema.resolve_path(&mod_path)? {
47 PathResolution::Def(ModuleDef::Module(it)) => it, 48 PathResolution::Def(ModuleDef::Module(it)) => it,
@@ -53,7 +54,6 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti
53 54
54 let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; 55 let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?;
55 let imported_defs = find_imported_defs(ctx, star)?; 56 let imported_defs = find_imported_defs(ctx, star)?;
56 let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
57 57
58 let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone()); 58 let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone());
59 acc.add( 59 acc.add(
@@ -61,9 +61,32 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti
61 "Expand glob import", 61 "Expand glob import",
62 target.text_range(), 62 target.text_range(),
63 |builder| { 63 |builder| {
64 let mut rewriter = SyntaxRewriter::default(); 64 let use_tree = builder.make_ast_mut(use_tree);
65 replace_ast(&mut rewriter, parent, mod_path, names_to_import); 65
66 builder.rewrite(rewriter); 66 let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
67 let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
68 let path =
69 make::path_unqualified(make::path_segment(make::name_ref(&n.to_string())));
70 make::use_tree(path, None, None, false)
71 }))
72 .clone_for_update();
73
74 match use_tree.star_token() {
75 Some(star) => {
76 let needs_braces = use_tree.path().is_some() && names_to_import.len() > 1;
77 if needs_braces {
78 ted::replace(star, expanded.syntax())
79 } else {
80 let without_braces = expanded
81 .syntax()
82 .children_with_tokens()
83 .filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
84 .collect();
85 ted::replace_with_many(star, without_braces)
86 }
87 }
88 None => never!(),
89 }
67 }, 90 },
68 ) 91 )
69} 92}
@@ -232,53 +255,6 @@ fn find_names_to_import(
232 used_refs.0.iter().map(|r| r.visible_name.clone()).collect() 255 used_refs.0.iter().map(|r| r.visible_name.clone()).collect()
233} 256}
234 257
235fn replace_ast(
236 rewriter: &mut SyntaxRewriter,
237 parent: Either<ast::UseTree, ast::UseTreeList>,
238 path: ast::Path,
239 names_to_import: Vec<Name>,
240) {
241 let existing_use_trees = match parent.clone() {
242 Either::Left(_) => vec![],
243 Either::Right(u) => u
244 .use_trees()
245 .filter(|n|
246 // filter out star
247 n.star_token().is_none())
248 .collect(),
249 };
250
251 let new_use_trees: Vec<ast::UseTree> = names_to_import
252 .iter()
253 .map(|n| {
254 let path = make::path_unqualified(make::path_segment(make::name_ref(&n.to_string())));
255 make::use_tree(path, None, None, false)
256 })
257 .collect();
258
259 let use_trees = [&existing_use_trees[..], &new_use_trees[..]].concat();
260
261 match use_trees.as_slice() {
262 [name] => {
263 if let Some(end_path) = name.path() {
264 rewriter.replace_ast(
265 &parent.left_or_else(|tl| tl.parent_use_tree()),
266 &make::use_tree(make::path_concat(path, end_path), None, None, false),
267 );
268 }
269 }
270 names => match &parent {
271 Either::Left(parent) => rewriter.replace_ast(
272 parent,
273 &make::use_tree(path, Some(make::use_tree_list(names.to_owned())), None, false),
274 ),
275 Either::Right(parent) => {
276 rewriter.replace_ast(parent, &make::use_tree_list(names.to_owned()))
277 }
278 },
279 };
280}
281
282#[cfg(test)] 258#[cfg(test)]
283mod tests { 259mod tests {
284 use crate::tests::{check_assist, check_assist_not_applicable}; 260 use crate::tests::{check_assist, check_assist_not_applicable};
@@ -350,7 +326,7 @@ mod foo {
350 pub fn f() {} 326 pub fn f() {}
351} 327}
352 328
353use foo::{f, Baz, Bar}; 329use foo::{Baz, Bar, f};
354 330
355fn qux(bar: Bar, baz: Baz) { 331fn qux(bar: Bar, baz: Baz) {
356 f(); 332 f();
@@ -389,7 +365,7 @@ mod foo {
389} 365}
390 366
391use foo::Bar; 367use foo::Bar;
392use foo::{f, Baz}; 368use foo::{Baz, f};
393 369
394fn qux(bar: Bar, baz: Baz) { 370fn qux(bar: Bar, baz: Baz) {
395 f(); 371 f();
@@ -439,7 +415,7 @@ mod foo {
439 } 415 }
440} 416}
441 417
442use foo::{bar::{f, Baz, Bar}, baz::*}; 418use foo::{bar::{Baz, Bar, f}, baz::*};
443 419
444fn qux(bar: Bar, baz: Baz) { 420fn qux(bar: Bar, baz: Baz) {
445 f(); 421 f();
@@ -891,7 +867,7 @@ mod foo {
891 pub struct Bar; 867 pub struct Bar;
892} 868}
893 869
894use foo::Bar; 870use foo::{Bar};
895 871
896struct Baz { 872struct Baz {
897 bar: Bar 873 bar: Bar