aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-01-29 14:35:28 +0000
committerGitHub <[email protected]>2020-01-29 14:35:28 +0000
commitb67f695956e17314b16f262cce9884f6d99c50dc (patch)
tree5b0a4d636639a6df2d079975590b14b0ae9afdec /crates/ra_assists/src/assists
parente3c81b67ffb97f5ac34af54d7c42033f7830bf2f (diff)
parent6d219c9a10a99e480c39c2382053105028d33247 (diff)
Merge #2942
2942: Properly select a target for auto importing r=matklad a=SomeoneToIgnore Fixes https://github.com/rust-analyzer/rust-analyzer/issues/2932 The corresponding test has the caret placed in the beggining of the document despite the import inserted, but I don't thing I should fix it here: * in real life, there's some text written before the import and for those cases the caret behaves normally * it's a separate functionality that needs to be refactored anyway later (the `auto_import_text_edit`) Co-authored-by: Kirill Bulatov <[email protected]>
Diffstat (limited to 'crates/ra_assists/src/assists')
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs46
1 files changed, 17 insertions, 29 deletions
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
index 9163cc662..69126a1c9 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -1,8 +1,8 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode}, 3 ast::{self, AstNode},
4 SmolStr, SyntaxElement, 4 SmolStr,
5 SyntaxKind::{NAME_REF, USE_ITEM}, 5 SyntaxKind::USE_ITEM,
6 SyntaxNode, 6 SyntaxNode,
7}; 7};
8 8
@@ -32,25 +32,28 @@ pub(crate) fn auto_import<F: ImportsLocator>(
32 ctx: AssistCtx<impl HirDatabase>, 32 ctx: AssistCtx<impl HirDatabase>,
33 imports_locator: &mut F, 33 imports_locator: &mut F,
34) -> Option<Assist> { 34) -> Option<Assist> {
35 let path: ast::Path = ctx.find_node_at_offset()?; 35 let path_to_import: ast::Path = ctx.find_node_at_offset()?;
36 let module = path.syntax().ancestors().find_map(ast::Module::cast); 36 let path_to_import_syntax = path_to_import.syntax();
37 if path_to_import_syntax.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() {
38 return None;
39 }
40
41 let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast);
37 let position = match module.and_then(|it| it.item_list()) { 42 let position = match module.and_then(|it| it.item_list()) {
38 Some(item_list) => item_list.syntax().clone(), 43 Some(item_list) => item_list.syntax().clone(),
39 None => { 44 None => {
40 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; 45 let current_file = path_to_import_syntax.ancestors().find_map(ast::SourceFile::cast)?;
41 current_file.syntax().clone() 46 current_file.syntax().clone()
42 } 47 }
43 }; 48 };
44 let source_analyzer = ctx.source_analyzer(&position, None); 49 let source_analyzer = ctx.source_analyzer(&position, None);
45 let module_with_name_to_import = source_analyzer.module()?; 50 let module_with_name_to_import = source_analyzer.module()?;
46 let path_to_import = ctx.covering_element().ancestors().find_map(ast::Path::cast)?;
47 if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() { 51 if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
48 return None; 52 return None;
49 } 53 }
50 54
51 let name_to_import = &find_applicable_name_ref(ctx.covering_element())?.syntax().to_string();
52 let proposed_imports = imports_locator 55 let proposed_imports = imports_locator
53 .find_imports(&name_to_import.to_string()) 56 .find_imports(&path_to_import_syntax.to_string())
54 .into_iter() 57 .into_iter()
55 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) 58 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
56 .filter(|use_path| !use_path.segments.is_empty()) 59 .filter(|use_path| !use_path.segments.is_empty())
@@ -64,26 +67,11 @@ pub(crate) fn auto_import<F: ImportsLocator>(
64 ctx.add_assist_group(AssistId("auto_import"), "auto import", || { 67 ctx.add_assist_group(AssistId("auto_import"), "auto import", || {
65 proposed_imports 68 proposed_imports
66 .into_iter() 69 .into_iter()
67 .map(|import| import_to_action(import, &position, &path_to_import.syntax())) 70 .map(|import| import_to_action(import, &position, &path_to_import_syntax))
68 .collect() 71 .collect()
69 }) 72 })
70} 73}
71 74
72fn find_applicable_name_ref(element: SyntaxElement) -> Option<ast::NameRef> {
73 if element.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() {
74 None
75 } else if element.kind() == NAME_REF {
76 Some(element.as_node().cloned().and_then(ast::NameRef::cast)?)
77 } else {
78 let parent = element.parent()?;
79 if parent.kind() == NAME_REF {
80 Some(ast::NameRef::cast(parent)?)
81 } else {
82 None
83 }
84 }
85}
86
87fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder { 75fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
88 let mut action_builder = ActionBuilder::default(); 76 let mut action_builder = ActionBuilder::default();
89 action_builder.label(format!("Import `{}`", &import)); 77 action_builder.label(format!("Import `{}`", &import));
@@ -110,16 +98,16 @@ mod tests {
110 auto_import, 98 auto_import,
111 TestImportsLocator::new, 99 TestImportsLocator::new,
112 r" 100 r"
113 PubStruct<|> 101 <|>PubStruct
114 102
115 pub mod PubMod { 103 pub mod PubMod {
116 pub struct PubStruct; 104 pub struct PubStruct;
117 } 105 }
118 ", 106 ",
119 r" 107 r"
120 use PubMod::PubStruct; 108 <|>use PubMod::PubStruct;
121 109
122 PubStruct<|> 110 PubStruct
123 111
124 pub mod PubMod { 112 pub mod PubMod {
125 pub struct PubStruct; 113 pub struct PubStruct;
@@ -134,7 +122,7 @@ mod tests {
134 auto_import, 122 auto_import,
135 TestImportsLocator::new, 123 TestImportsLocator::new,
136 r" 124 r"
137 PubStruct<|> 125 PubSt<|>ruct
138 126
139 pub mod PubMod1 { 127 pub mod PubMod1 {
140 pub struct PubStruct; 128 pub struct PubStruct;
@@ -149,7 +137,7 @@ mod tests {
149 r" 137 r"
150 use PubMod1::PubStruct; 138 use PubMod1::PubStruct;
151 139
152 PubStruct<|> 140 PubSt<|>ruct
153 141
154 pub mod PubMod1 { 142 pub mod PubMod1 {
155 pub struct PubStruct; 143 pub struct PubStruct;