diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/handlers/expand_glob_import.rs | 78 |
1 files changed, 65 insertions, 13 deletions
diff --git a/crates/ra_assists/src/handlers/expand_glob_import.rs b/crates/ra_assists/src/handlers/expand_glob_import.rs index 1eb8070ad..978c6772e 100644 --- a/crates/ra_assists/src/handlers/expand_glob_import.rs +++ b/crates/ra_assists/src/handlers/expand_glob_import.rs | |||
@@ -1,15 +1,17 @@ | |||
1 | use hir::{MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope}; | 1 | use hir::{AssocItem, MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope}; |
2 | use ra_ide_db::{ | 2 | use ra_ide_db::{ |
3 | defs::{classify_name_ref, Definition, NameRefClass}, | 3 | defs::{classify_name_ref, Definition, NameRefClass}, |
4 | RootDatabase, | 4 | RootDatabase, |
5 | }; | 5 | }; |
6 | use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T}; | 6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T}; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | assist_context::{AssistBuilder, AssistContext, Assists}, | 9 | assist_context::{AssistBuilder, AssistContext, Assists}, |
10 | AssistId, AssistKind, | 10 | AssistId, AssistKind, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use either::Either; | ||
14 | |||
13 | // Assist: expand_glob_import | 15 | // Assist: expand_glob_import |
14 | // | 16 | // |
15 | // Expands glob imports. | 17 | // Expands glob imports. |
@@ -122,7 +124,19 @@ fn find_used_names( | |||
122 | 124 | ||
123 | defs_in_mod | 125 | defs_in_mod |
124 | .iter() | 126 | .iter() |
125 | .filter(|d| defs_in_source_file.contains(d)) | 127 | .filter(|def| { |
128 | if let Def::ModuleDef(ModuleDef::Trait(tr)) = def { | ||
129 | for item in tr.items(ctx.db()) { | ||
130 | if let AssocItem::Function(f) = item { | ||
131 | if defs_in_source_file.contains(&Def::ModuleDef(ModuleDef::Function(f))) { | ||
132 | return true; | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | defs_in_source_file.contains(def) | ||
139 | }) | ||
126 | .filter_map(|d| d.name(ctx.db())) | 140 | .filter_map(|d| d.name(ctx.db())) |
127 | .collect() | 141 | .collect() |
128 | } | 142 | } |
@@ -133,28 +147,38 @@ fn replace_ast( | |||
133 | path: ast::Path, | 147 | path: ast::Path, |
134 | used_names: Vec<Name>, | 148 | used_names: Vec<Name>, |
135 | ) { | 149 | ) { |
136 | let new_use_tree_list = ast::make::use_tree_list(used_names.iter().map(|n| { | 150 | let replacement: Either<ast::UseTree, ast::UseTreeList> = if used_names.len() == 1 { |
137 | ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false) | 151 | Either::Left(ast::make::use_tree( |
138 | })); | 152 | ast::make::path_from_text(&format!("{}::{}", path, used_names.first().unwrap())), |
153 | None, | ||
154 | None, | ||
155 | false, | ||
156 | )) | ||
157 | } else { | ||
158 | Either::Right(ast::make::use_tree_list(used_names.iter().map(|n| { | ||
159 | ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false) | ||
160 | }))) | ||
161 | }; | ||
162 | |||
163 | let mut replace_node = |replacement: Either<ast::UseTree, ast::UseTreeList>| { | ||
164 | algo::diff(node, &replacement.either(|u| u.syntax().clone(), |ut| ut.syntax().clone())) | ||
165 | .into_text_edit(builder.text_edit_builder()); | ||
166 | }; | ||
139 | 167 | ||
140 | match_ast! { | 168 | match_ast! { |
141 | match node { | 169 | match node { |
142 | ast::UseTree(use_tree) => { | 170 | ast::UseTree(use_tree) => { |
143 | builder.replace_ast(use_tree, make_use_tree(path, new_use_tree_list)); | 171 | replace_node(replacement); |
144 | }, | 172 | }, |
145 | ast::UseTreeList(use_tree_list) => { | 173 | ast::UseTreeList(use_tree_list) => { |
146 | builder.replace_ast(use_tree_list, new_use_tree_list); | 174 | replace_node(replacement); |
147 | }, | 175 | }, |
148 | ast::Use(use_item) => { | 176 | ast::Use(use_item) => { |
149 | builder.replace_ast(use_item, ast::make::use_item(make_use_tree(path, new_use_tree_list))); | 177 | builder.replace_ast(use_item, ast::make::use_item(replacement.left_or_else(|ut| ast::make::use_tree(path, Some(ut), None, false)))); |
150 | }, | 178 | }, |
151 | _ => {}, | 179 | _ => {}, |
152 | } | 180 | } |
153 | } | 181 | } |
154 | |||
155 | fn make_use_tree(path: ast::Path, use_tree_list: ast::UseTreeList) -> ast::UseTree { | ||
156 | ast::make::use_tree(path, Some(use_tree_list), None, false) | ||
157 | } | ||
158 | } | 182 | } |
159 | 183 | ||
160 | #[cfg(test)] | 184 | #[cfg(test)] |
@@ -321,6 +345,34 @@ fn main() { | |||
321 | } | 345 | } |
322 | 346 | ||
323 | #[test] | 347 | #[test] |
348 | fn expanding_glob_import_with_trait_method_uses() { | ||
349 | check_assist( | ||
350 | expand_glob_import, | ||
351 | r" | ||
352 | //- /lib.rs crate:foo | ||
353 | pub trait Tr { | ||
354 | fn method(&self) {} | ||
355 | } | ||
356 | impl Tr for () {} | ||
357 | |||
358 | //- /main.rs crate:main deps:foo | ||
359 | use foo::*<|>; | ||
360 | |||
361 | fn main() { | ||
362 | ().method(); | ||
363 | } | ||
364 | ", | ||
365 | r" | ||
366 | use foo::Tr; | ||
367 | |||
368 | fn main() { | ||
369 | ().method(); | ||
370 | } | ||
371 | ", | ||
372 | ) | ||
373 | } | ||
374 | |||
375 | #[test] | ||
324 | fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() { | 376 | fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() { |
325 | check_assist_not_applicable( | 377 | check_assist_not_applicable( |
326 | expand_glob_import, | 378 | expand_glob_import, |