Skip to content

Commit 5214b4c

Browse files
committed
Look for trait methods in expand glob import assist
1 parent bdb9775 commit 5214b4c

File tree

1 file changed

+65
-13
lines changed

1 file changed

+65
-13
lines changed

crates/ra_assists/src/handlers/expand_glob_import.rs

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
use hir::{MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope};
1+
use hir::{AssocItem, MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope};
22
use ra_ide_db::{
33
defs::{classify_name_ref, Definition, NameRefClass},
44
RootDatabase,
55
};
6-
use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T};
6+
use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T};
77

88
use crate::{
99
assist_context::{AssistBuilder, AssistContext, Assists},
1010
AssistId, AssistKind,
1111
};
1212

13+
use either::Either;
14+
1315
// Assist: expand_glob_import
1416
//
1517
// Expands glob imports.
@@ -122,7 +124,19 @@ fn find_used_names(
122124

123125
defs_in_mod
124126
.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+
})
126140
.filter_map(|d| d.name(ctx.db()))
127141
.collect()
128142
}
@@ -133,28 +147,38 @@ fn replace_ast(
133147
path: ast::Path,
134148
used_names: Vec<Name>,
135149
) {
136-
let new_use_tree_list = ast::make::use_tree_list(used_names.iter().map(|n| {
137-
ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false)
138-
}));
150+
let replacement: Either<ast::UseTree, ast::UseTreeList> = if used_names.len() == 1 {
151+
Either::Left(ast::make::use_tree(
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+
};
139167

140168
match_ast! {
141169
match node {
142170
ast::UseTree(use_tree) => {
143-
builder.replace_ast(use_tree, make_use_tree(path, new_use_tree_list));
171+
replace_node(replacement);
144172
},
145173
ast::UseTreeList(use_tree_list) => {
146-
builder.replace_ast(use_tree_list, new_use_tree_list);
174+
replace_node(replacement);
147175
},
148176
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))));
150178
},
151179
_ => {},
152180
}
153181
}
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-
}
158182
}
159183

160184
#[cfg(test)]
@@ -320,6 +344,34 @@ fn main() {
320344
)
321345
}
322346

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+
323375
#[test]
324376
fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() {
325377
check_assist_not_applicable(

0 commit comments

Comments
 (0)