diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/assists/auto_import.rs | 39 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 158 | ||||
-rw-r--r-- | crates/ra_ide/src/assists.rs | 2 |
3 files changed, 21 insertions, 178 deletions
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index 48ab336b1..219051063 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs | |||
@@ -6,8 +6,9 @@ use ra_syntax::{ | |||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | assist_ctx::{ActionBuilder, Assist, AssistCtx}, | 8 | assist_ctx::{ActionBuilder, Assist, AssistCtx}, |
9 | auto_import_text_edit, AssistId, ImportsLocator, | 9 | auto_import_text_edit, AssistId, |
10 | }; | 10 | }; |
11 | use ra_ide_db::imports_locator::ImportsLocatorIde; | ||
11 | 12 | ||
12 | // Assist: auto_import | 13 | // Assist: auto_import |
13 | // | 14 | // |
@@ -26,10 +27,7 @@ use crate::{ | |||
26 | // let map = HashMap<|>::new(); | 27 | // let map = HashMap<|>::new(); |
27 | // } | 28 | // } |
28 | // ``` | 29 | // ``` |
29 | pub(crate) fn auto_import<F: ImportsLocator>( | 30 | pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { |
30 | ctx: AssistCtx, | ||
31 | imports_locator: &mut F, | ||
32 | ) -> Option<Assist> { | ||
33 | let path_to_import: ast::Path = ctx.find_node_at_offset()?; | 31 | let path_to_import: ast::Path = ctx.find_node_at_offset()?; |
34 | let path_to_import_syntax = path_to_import.syntax(); | 32 | let path_to_import_syntax = path_to_import.syntax(); |
35 | if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() { | 33 | if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() { |
@@ -52,6 +50,8 @@ pub(crate) fn auto_import<F: ImportsLocator>( | |||
52 | return None; | 50 | return None; |
53 | } | 51 | } |
54 | 52 | ||
53 | let mut imports_locator = ImportsLocatorIde::new(ctx.db); | ||
54 | |||
55 | let proposed_imports = imports_locator | 55 | let proposed_imports = imports_locator |
56 | .find_imports(&name_to_import) | 56 | .find_imports(&name_to_import) |
57 | .into_iter() | 57 | .into_iter() |
@@ -81,16 +81,12 @@ fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode) | |||
81 | #[cfg(test)] | 81 | #[cfg(test)] |
82 | mod tests { | 82 | mod tests { |
83 | use super::*; | 83 | use super::*; |
84 | use crate::helpers::{ | 84 | use crate::helpers::{check_assist, check_assist_not_applicable}; |
85 | check_assist_with_imports_locator, check_assist_with_imports_locator_not_applicable, | ||
86 | TestImportsLocator, | ||
87 | }; | ||
88 | 85 | ||
89 | #[test] | 86 | #[test] |
90 | fn applicable_when_found_an_import() { | 87 | fn applicable_when_found_an_import() { |
91 | check_assist_with_imports_locator( | 88 | check_assist( |
92 | auto_import, | 89 | auto_import, |
93 | TestImportsLocator::new, | ||
94 | r" | 90 | r" |
95 | <|>PubStruct | 91 | <|>PubStruct |
96 | 92 | ||
@@ -112,9 +108,8 @@ mod tests { | |||
112 | 108 | ||
113 | #[test] | 109 | #[test] |
114 | fn auto_imports_are_merged() { | 110 | fn auto_imports_are_merged() { |
115 | check_assist_with_imports_locator( | 111 | check_assist( |
116 | auto_import, | 112 | auto_import, |
117 | TestImportsLocator::new, | ||
118 | r" | 113 | r" |
119 | use PubMod::PubStruct1; | 114 | use PubMod::PubStruct1; |
120 | 115 | ||
@@ -148,9 +143,8 @@ mod tests { | |||
148 | 143 | ||
149 | #[test] | 144 | #[test] |
150 | fn applicable_when_found_multiple_imports() { | 145 | fn applicable_when_found_multiple_imports() { |
151 | check_assist_with_imports_locator( | 146 | check_assist( |
152 | auto_import, | 147 | auto_import, |
153 | TestImportsLocator::new, | ||
154 | r" | 148 | r" |
155 | PubSt<|>ruct | 149 | PubSt<|>ruct |
156 | 150 | ||
@@ -184,9 +178,8 @@ mod tests { | |||
184 | 178 | ||
185 | #[test] | 179 | #[test] |
186 | fn not_applicable_for_already_imported_types() { | 180 | fn not_applicable_for_already_imported_types() { |
187 | check_assist_with_imports_locator_not_applicable( | 181 | check_assist_not_applicable( |
188 | auto_import, | 182 | auto_import, |
189 | TestImportsLocator::new, | ||
190 | r" | 183 | r" |
191 | use PubMod::PubStruct; | 184 | use PubMod::PubStruct; |
192 | 185 | ||
@@ -201,9 +194,8 @@ mod tests { | |||
201 | 194 | ||
202 | #[test] | 195 | #[test] |
203 | fn not_applicable_for_types_with_private_paths() { | 196 | fn not_applicable_for_types_with_private_paths() { |
204 | check_assist_with_imports_locator_not_applicable( | 197 | check_assist_not_applicable( |
205 | auto_import, | 198 | auto_import, |
206 | TestImportsLocator::new, | ||
207 | r" | 199 | r" |
208 | PrivateStruct<|> | 200 | PrivateStruct<|> |
209 | 201 | ||
@@ -216,9 +208,8 @@ mod tests { | |||
216 | 208 | ||
217 | #[test] | 209 | #[test] |
218 | fn not_applicable_when_no_imports_found() { | 210 | fn not_applicable_when_no_imports_found() { |
219 | check_assist_with_imports_locator_not_applicable( | 211 | check_assist_not_applicable( |
220 | auto_import, | 212 | auto_import, |
221 | TestImportsLocator::new, | ||
222 | " | 213 | " |
223 | PubStruct<|>", | 214 | PubStruct<|>", |
224 | ); | 215 | ); |
@@ -226,9 +217,8 @@ mod tests { | |||
226 | 217 | ||
227 | #[test] | 218 | #[test] |
228 | fn not_applicable_in_import_statements() { | 219 | fn not_applicable_in_import_statements() { |
229 | check_assist_with_imports_locator_not_applicable( | 220 | check_assist_not_applicable( |
230 | auto_import, | 221 | auto_import, |
231 | TestImportsLocator::new, | ||
232 | r" | 222 | r" |
233 | use PubStruct<|>; | 223 | use PubStruct<|>; |
234 | 224 | ||
@@ -240,9 +230,8 @@ mod tests { | |||
240 | 230 | ||
241 | #[test] | 231 | #[test] |
242 | fn function_import() { | 232 | fn function_import() { |
243 | check_assist_with_imports_locator( | 233 | check_assist( |
244 | auto_import, | 234 | auto_import, |
245 | TestImportsLocator::new, | ||
246 | r" | 235 | r" |
247 | test_function<|> | 236 | test_function<|> |
248 | 237 | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index ad8438b6c..8285e93a4 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -12,9 +12,8 @@ mod doc_tests; | |||
12 | pub mod ast_transform; | 12 | pub mod ast_transform; |
13 | 13 | ||
14 | use either::Either; | 14 | use either::Either; |
15 | use hir::ModuleDef; | ||
16 | use ra_db::FileRange; | 15 | use ra_db::FileRange; |
17 | use ra_ide_db::{imports_locator::ImportsLocatorIde, RootDatabase}; | 16 | use ra_ide_db::RootDatabase; |
18 | use ra_syntax::{TextRange, TextUnit}; | 17 | use ra_syntax::{TextRange, TextUnit}; |
19 | use ra_text_edit::TextEdit; | 18 | use ra_text_edit::TextEdit; |
20 | 19 | ||
@@ -73,50 +72,6 @@ pub fn applicable_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabe | |||
73 | }) | 72 | }) |
74 | } | 73 | } |
75 | 74 | ||
76 | /// A functionality for locating imports for the given name. | ||
77 | /// | ||
78 | /// Currently has to be a trait with the real implementation provided by the ra_ide_api crate, | ||
79 | /// due to the search functionality located there. | ||
80 | /// Later, this trait should be removed completely and the search functionality moved to a separate crate, | ||
81 | /// accessible from the ra_assists crate. | ||
82 | pub trait ImportsLocator { | ||
83 | /// Finds all imports for the given name and the module that contains this name. | ||
84 | fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef>; | ||
85 | } | ||
86 | |||
87 | impl ImportsLocator for ImportsLocatorIde<'_> { | ||
88 | fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> { | ||
89 | self.find_imports(name_to_import) | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /// Return all the assists applicable at the given position | ||
94 | /// and additional assists that need the imports locator functionality to work. | ||
95 | /// | ||
96 | /// Assists are returned in the "resolved" state, that is with edit fully | ||
97 | /// computed. | ||
98 | pub fn assists_with_imports_locator(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { | ||
99 | let mut imports_locator = ImportsLocatorIde::new(db); | ||
100 | AssistCtx::with_ctx(db, range, true, |ctx| { | ||
101 | let mut assists = assists::all() | ||
102 | .iter() | ||
103 | .map(|f| f(ctx.clone())) | ||
104 | .chain( | ||
105 | assists::all_with_imports_locator() | ||
106 | .iter() | ||
107 | .map(|f| f(ctx.clone(), &mut imports_locator)), | ||
108 | ) | ||
109 | .filter_map(std::convert::identity) | ||
110 | .map(|a| match a { | ||
111 | Assist::Resolved { assist } => assist, | ||
112 | Assist::Unresolved { .. } => unreachable!(), | ||
113 | }) | ||
114 | .collect(); | ||
115 | sort_assists(&mut assists); | ||
116 | assists | ||
117 | }) | ||
118 | } | ||
119 | |||
120 | /// Return all the assists applicable at the given position. | 75 | /// Return all the assists applicable at the given position. |
121 | /// | 76 | /// |
122 | /// Assists are returned in the "resolved" state, that is with edit fully | 77 | /// Assists are returned in the "resolved" state, that is with edit fully |
@@ -147,7 +102,7 @@ fn sort_assists(assists: &mut Vec<ResolvedAssist>) { | |||
147 | } | 102 | } |
148 | 103 | ||
149 | mod assists { | 104 | mod assists { |
150 | use crate::{Assist, AssistCtx, ImportsLocator}; | 105 | use crate::{Assist, AssistCtx}; |
151 | 106 | ||
152 | mod add_derive; | 107 | mod add_derive; |
153 | mod add_explicit_type; | 108 | mod add_explicit_type; |
@@ -206,72 +161,19 @@ mod assists { | |||
206 | raw_string::make_usual_string, | 161 | raw_string::make_usual_string, |
207 | raw_string::remove_hash, | 162 | raw_string::remove_hash, |
208 | early_return::convert_to_guarded_return, | 163 | early_return::convert_to_guarded_return, |
164 | auto_import::auto_import, | ||
209 | ] | 165 | ] |
210 | } | 166 | } |
211 | |||
212 | pub(crate) fn all_with_imports_locator<'a, F: ImportsLocator>( | ||
213 | ) -> &'a [fn(AssistCtx, &mut F) -> Option<Assist>] { | ||
214 | &[auto_import::auto_import] | ||
215 | } | ||
216 | } | 167 | } |
217 | 168 | ||
218 | #[cfg(test)] | 169 | #[cfg(test)] |
219 | mod helpers { | 170 | mod helpers { |
220 | use hir::db::DefDatabase; | 171 | use ra_db::{fixture::WithFixture, FileRange}; |
221 | use ra_db::{fixture::WithFixture, FileId, FileRange}; | 172 | use ra_ide_db::RootDatabase; |
222 | use ra_syntax::TextRange; | 173 | use ra_syntax::TextRange; |
223 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | 174 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; |
224 | 175 | ||
225 | use crate::{Assist, AssistCtx, ImportsLocator}; | 176 | use crate::{Assist, AssistCtx}; |
226 | use ra_ide_db::RootDatabase; | ||
227 | use std::sync::Arc; | ||
228 | |||
229 | // FIXME remove the `ModuleDefId` reexport from `ra_hir` when this gets removed. | ||
230 | pub(crate) struct TestImportsLocator { | ||
231 | db: Arc<RootDatabase>, | ||
232 | test_file_id: FileId, | ||
233 | } | ||
234 | |||
235 | impl TestImportsLocator { | ||
236 | pub(crate) fn new(db: Arc<RootDatabase>, test_file_id: FileId) -> Self { | ||
237 | TestImportsLocator { db, test_file_id } | ||
238 | } | ||
239 | } | ||
240 | |||
241 | impl ImportsLocator for TestImportsLocator { | ||
242 | fn find_imports(&mut self, name_to_import: &str) -> Vec<hir::ModuleDef> { | ||
243 | let crate_def_map = self.db.crate_def_map(self.db.test_crate()); | ||
244 | let mut findings = Vec::new(); | ||
245 | |||
246 | let mut module_ids_to_process = | ||
247 | crate_def_map.modules_for_file(self.test_file_id).collect::<Vec<_>>(); | ||
248 | |||
249 | while !module_ids_to_process.is_empty() { | ||
250 | let mut more_ids_to_process = Vec::new(); | ||
251 | for local_module_id in module_ids_to_process.drain(..) { | ||
252 | for (name, namespace_data) in | ||
253 | crate_def_map[local_module_id].scope.entries_without_primitives() | ||
254 | { | ||
255 | let found_a_match = &name.to_string() == name_to_import; | ||
256 | vec![namespace_data.types, namespace_data.values] | ||
257 | .into_iter() | ||
258 | .filter_map(std::convert::identity) | ||
259 | .for_each(|(module_def_id, _)| { | ||
260 | if found_a_match { | ||
261 | findings.push(module_def_id.into()); | ||
262 | } | ||
263 | if let hir::ModuleDefId::ModuleId(module_id) = module_def_id { | ||
264 | more_ids_to_process.push(module_id.local_id); | ||
265 | } | ||
266 | }); | ||
267 | } | ||
268 | } | ||
269 | module_ids_to_process = more_ids_to_process; | ||
270 | } | ||
271 | |||
272 | findings | ||
273 | } | ||
274 | } | ||
275 | 177 | ||
276 | pub(crate) fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) { | 178 | pub(crate) fn check_assist(assist: fn(AssistCtx) -> Option<Assist>, before: &str, after: &str) { |
277 | let (before_cursor_pos, before) = extract_offset(before); | 179 | let (before_cursor_pos, before) = extract_offset(before); |
@@ -297,38 +199,6 @@ mod helpers { | |||
297 | assert_eq_text!(after, &actual); | 199 | assert_eq_text!(after, &actual); |
298 | } | 200 | } |
299 | 201 | ||
300 | pub(crate) fn check_assist_with_imports_locator<F: ImportsLocator>( | ||
301 | assist: fn(AssistCtx, &mut F) -> Option<Assist>, | ||
302 | imports_locator_provider: fn(db: Arc<RootDatabase>, file_id: FileId) -> F, | ||
303 | before: &str, | ||
304 | after: &str, | ||
305 | ) { | ||
306 | let (before_cursor_pos, before) = extract_offset(before); | ||
307 | let (db, file_id) = RootDatabase::with_single_file(&before); | ||
308 | let db = Arc::new(db); | ||
309 | let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id); | ||
310 | let frange = | ||
311 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | ||
312 | let assist = | ||
313 | AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator)) | ||
314 | .expect("code action is not applicable"); | ||
315 | let action = match assist { | ||
316 | Assist::Unresolved { .. } => unreachable!(), | ||
317 | Assist::Resolved { assist } => assist.get_first_action(), | ||
318 | }; | ||
319 | |||
320 | let actual = action.edit.apply(&before); | ||
321 | let actual_cursor_pos = match action.cursor_position { | ||
322 | None => action | ||
323 | .edit | ||
324 | .apply_to_offset(before_cursor_pos) | ||
325 | .expect("cursor position is affected by the edit"), | ||
326 | Some(off) => off, | ||
327 | }; | ||
328 | let actual = add_cursor(&actual, actual_cursor_pos); | ||
329 | assert_eq_text!(after, &actual); | ||
330 | } | ||
331 | |||
332 | pub(crate) fn check_assist_range( | 202 | pub(crate) fn check_assist_range( |
333 | assist: fn(AssistCtx) -> Option<Assist>, | 203 | assist: fn(AssistCtx) -> Option<Assist>, |
334 | before: &str, | 204 | before: &str, |
@@ -402,22 +272,6 @@ mod helpers { | |||
402 | assert!(assist.is_none()); | 272 | assert!(assist.is_none()); |
403 | } | 273 | } |
404 | 274 | ||
405 | pub(crate) fn check_assist_with_imports_locator_not_applicable<F: ImportsLocator>( | ||
406 | assist: fn(AssistCtx, &mut F) -> Option<Assist>, | ||
407 | imports_locator_provider: fn(db: Arc<RootDatabase>, file_id: FileId) -> F, | ||
408 | before: &str, | ||
409 | ) { | ||
410 | let (before_cursor_pos, before) = extract_offset(before); | ||
411 | let (db, file_id) = RootDatabase::with_single_file(&before); | ||
412 | let db = Arc::new(db); | ||
413 | let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id); | ||
414 | let frange = | ||
415 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | ||
416 | let assist = | ||
417 | AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator)); | ||
418 | assert!(assist.is_none()); | ||
419 | } | ||
420 | |||
421 | pub(crate) fn check_assist_range_not_applicable( | 275 | pub(crate) fn check_assist_range_not_applicable( |
422 | assist: fn(AssistCtx) -> Option<Assist>, | 276 | assist: fn(AssistCtx) -> Option<Assist>, |
423 | before: &str, | 277 | before: &str, |
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs index 6ee617e79..c3b2c638b 100644 --- a/crates/ra_ide/src/assists.rs +++ b/crates/ra_ide/src/assists.rs | |||
@@ -17,7 +17,7 @@ pub struct Assist { | |||
17 | } | 17 | } |
18 | 18 | ||
19 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { | 19 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { |
20 | ra_assists::assists_with_imports_locator(db, frange) | 20 | ra_assists::assists(db, frange) |
21 | .into_iter() | 21 | .into_iter() |
22 | .map(|assist| { | 22 | .map(|assist| { |
23 | let file_id = frange.file_id; | 23 | let file_id = frange.file_id; |