aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
authorunexge <[email protected]>2020-08-05 09:29:00 +0100
committerunexge <[email protected]>2020-08-05 09:29:00 +0100
commit5214b4cdba2c4976cb1ca4724a008268cdaf3e61 (patch)
treebe3b93fe0c05cdc029cb7424fc1801689e8f9726 /crates/ra_assists/src/handlers
parentbdb97756ca4c2710061fc49a5e2c2c10f5cc1eb6 (diff)
Look for trait methods in expand glob import assist
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/expand_glob_import.rs78
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 @@
1use hir::{MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope}; 1use hir::{AssocItem, MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope};
2use ra_ide_db::{ 2use ra_ide_db::{
3 defs::{classify_name_ref, Definition, NameRefClass}, 3 defs::{classify_name_ref, Definition, NameRefClass},
4 RootDatabase, 4 RootDatabase,
5}; 5};
6use ra_syntax::{ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T}; 6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T};
7 7
8use crate::{ 8use crate::{
9 assist_context::{AssistBuilder, AssistContext, Assists}, 9 assist_context::{AssistBuilder, AssistContext, Assists},
10 AssistId, AssistKind, 10 AssistId, AssistKind,
11}; 11};
12 12
13use 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
353pub trait Tr {
354 fn method(&self) {}
355}
356impl Tr for () {}
357
358//- /main.rs crate:main deps:foo
359use foo::*<|>;
360
361fn main() {
362 ().method();
363}
364",
365 r"
366use foo::Tr;
367
368fn 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,