diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/assists/auto_import.rs | 144 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 66 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 |
3 files changed, 150 insertions, 61 deletions
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index d196f6c5c..295fdf2e2 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs | |||
@@ -100,88 +100,122 @@ mod tests { | |||
100 | use super::*; | 100 | use super::*; |
101 | use crate::helpers::{ | 101 | use crate::helpers::{ |
102 | check_assist_with_imports_locator, check_assist_with_imports_locator_not_applicable, | 102 | check_assist_with_imports_locator, check_assist_with_imports_locator_not_applicable, |
103 | TestImportsLocator, | ||
103 | }; | 104 | }; |
104 | use hir::Name; | ||
105 | 105 | ||
106 | #[derive(Clone)] | 106 | #[test] |
107 | struct TestImportsLocator<'a> { | 107 | fn applicable_when_found_an_import() { |
108 | import_path: &'a [Name], | 108 | check_assist_with_imports_locator( |
109 | } | 109 | auto_import, |
110 | TestImportsLocator::new, | ||
111 | r" | ||
112 | PubStruct<|> | ||
110 | 113 | ||
111 | impl<'a> TestImportsLocator<'a> { | 114 | pub mod PubMod { |
112 | fn new(import_path: &'a [Name]) -> Self { | 115 | pub struct PubStruct; |
113 | TestImportsLocator { import_path } | 116 | } |
114 | } | 117 | ", |
115 | } | 118 | r" |
119 | use PubMod::PubStruct; | ||
116 | 120 | ||
117 | impl<'a> ImportsLocator for TestImportsLocator<'a> { | 121 | PubStruct<|> |
118 | fn find_imports( | 122 | |
119 | &mut self, | 123 | pub mod PubMod { |
120 | _: hir::InFile<&ast::NameRef>, | 124 | pub struct PubStruct; |
121 | _: hir::Module, | ||
122 | ) -> Option<Vec<hir::ModPath>> { | ||
123 | if self.import_path.is_empty() { | ||
124 | None | ||
125 | } else { | ||
126 | Some(vec![hir::ModPath { | ||
127 | kind: hir::PathKind::Plain, | ||
128 | segments: self.import_path.to_owned(), | ||
129 | }]) | ||
130 | } | 125 | } |
131 | } | 126 | ", |
127 | ); | ||
132 | } | 128 | } |
133 | 129 | ||
134 | #[test] | 130 | #[test] |
135 | fn applicable_when_found_an_import() { | 131 | fn applicable_when_found_multiple_imports() { |
136 | let import_path = &[hir::name::known::std, hir::name::known::ops, hir::name::known::Debug]; | ||
137 | let mut imports_locator = TestImportsLocator::new(import_path); | ||
138 | check_assist_with_imports_locator( | 132 | check_assist_with_imports_locator( |
139 | auto_import, | 133 | auto_import, |
140 | &mut imports_locator, | 134 | TestImportsLocator::new, |
141 | " | 135 | r" |
142 | fn main() { | 136 | PubStruct<|> |
137 | |||
138 | pub mod PubMod1 { | ||
139 | pub struct PubStruct; | ||
140 | } | ||
141 | pub mod PubMod2 { | ||
142 | pub struct PubStruct; | ||
143 | } | ||
144 | pub mod PubMod3 { | ||
145 | pub struct PubStruct; | ||
146 | } | ||
147 | ", | ||
148 | r" | ||
149 | use PubMod1::PubStruct; | ||
150 | |||
151 | PubStruct<|> | ||
152 | |||
153 | pub mod PubMod1 { | ||
154 | pub struct PubStruct; | ||
155 | } | ||
156 | pub mod PubMod2 { | ||
157 | pub struct PubStruct; | ||
143 | } | 158 | } |
159 | pub mod PubMod3 { | ||
160 | pub struct PubStruct; | ||
161 | } | ||
162 | ", | ||
163 | ); | ||
164 | } | ||
165 | |||
166 | #[test] | ||
167 | fn not_applicable_for_already_imported_types() { | ||
168 | check_assist_with_imports_locator_not_applicable( | ||
169 | auto_import, | ||
170 | TestImportsLocator::new, | ||
171 | r" | ||
172 | use PubMod::PubStruct; | ||
173 | |||
174 | PubStruct<|> | ||
144 | 175 | ||
145 | Debug<|>", | 176 | pub mod PubMod { |
146 | &format!( | 177 | pub struct PubStruct; |
147 | " | 178 | } |
148 | use {}; | 179 | ", |
149 | |||
150 | fn main() {{ | ||
151 | }} | ||
152 | |||
153 | Debug<|>", | ||
154 | import_path | ||
155 | .into_iter() | ||
156 | .map(|name| name.to_string()) | ||
157 | .collect::<Vec<String>>() | ||
158 | .join("::") | ||
159 | ), | ||
160 | ); | 180 | ); |
161 | } | 181 | } |
162 | 182 | ||
163 | #[test] | 183 | #[test] |
164 | fn not_applicable_when_no_imports_found() { | 184 | fn not_applicable_for_types_with_private_paths() { |
165 | let mut imports_locator = TestImportsLocator::new(&[]); | ||
166 | check_assist_with_imports_locator_not_applicable( | 185 | check_assist_with_imports_locator_not_applicable( |
167 | auto_import, | 186 | auto_import, |
168 | &mut imports_locator, | 187 | TestImportsLocator::new, |
169 | " | 188 | r" |
170 | fn main() { | 189 | PrivateStruct<|> |
190 | |||
191 | pub mod PubMod { | ||
192 | struct PrivateStruct; | ||
171 | } | 193 | } |
194 | ", | ||
195 | ); | ||
196 | } | ||
172 | 197 | ||
173 | Debug<|>", | 198 | #[test] |
199 | fn not_applicable_when_no_imports_found() { | ||
200 | check_assist_with_imports_locator_not_applicable( | ||
201 | auto_import, | ||
202 | TestImportsLocator::new, | ||
203 | " | ||
204 | PubStruct<|>", | ||
174 | ); | 205 | ); |
175 | } | 206 | } |
176 | 207 | ||
177 | #[test] | 208 | #[test] |
178 | fn not_applicable_in_import_statements() { | 209 | fn not_applicable_in_import_statements() { |
179 | let import_path = &[hir::name::known::std, hir::name::known::ops, hir::name::known::Debug]; | ||
180 | let mut imports_locator = TestImportsLocator::new(import_path); | ||
181 | check_assist_with_imports_locator_not_applicable( | 210 | check_assist_with_imports_locator_not_applicable( |
182 | auto_import, | 211 | auto_import, |
183 | &mut imports_locator, | 212 | TestImportsLocator::new, |
184 | "use Debug<|>;", | 213 | r" |
214 | use PubStruct<|>; | ||
215 | |||
216 | pub mod PubMod { | ||
217 | pub struct PubStruct; | ||
218 | }", | ||
185 | ); | 219 | ); |
186 | } | 220 | } |
187 | } | 221 | } |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 9e4ebec47..724bce191 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -226,11 +226,59 @@ mod assists { | |||
226 | 226 | ||
227 | #[cfg(test)] | 227 | #[cfg(test)] |
228 | mod helpers { | 228 | mod helpers { |
229 | use ra_db::{fixture::WithFixture, FileRange}; | 229 | use hir::db::DefDatabase; |
230 | use ra_db::{fixture::WithFixture, FileId, FileRange}; | ||
230 | use ra_syntax::TextRange; | 231 | use ra_syntax::TextRange; |
231 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | 232 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; |
232 | 233 | ||
233 | use crate::{test_db::TestDB, Assist, AssistCtx, ImportsLocator}; | 234 | use crate::{test_db::TestDB, Assist, AssistCtx, ImportsLocator}; |
235 | use std::sync::Arc; | ||
236 | |||
237 | pub(crate) struct TestImportsLocator { | ||
238 | db: Arc<TestDB>, | ||
239 | test_file_id: FileId, | ||
240 | } | ||
241 | |||
242 | impl TestImportsLocator { | ||
243 | pub(crate) fn new(db: Arc<TestDB>, test_file_id: FileId) -> Self { | ||
244 | TestImportsLocator { db, test_file_id } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | impl ImportsLocator for TestImportsLocator { | ||
249 | fn find_imports(&mut self, name_to_import: &str) -> Vec<hir::ModuleDef> { | ||
250 | let crate_def_map = self.db.crate_def_map(self.db.test_crate()); | ||
251 | let mut findings = vec![]; | ||
252 | |||
253 | let mut module_ids_to_process = | ||
254 | crate_def_map.modules_for_file(self.test_file_id).collect::<Vec<_>>(); | ||
255 | |||
256 | while !module_ids_to_process.is_empty() { | ||
257 | let mut more_ids_to_process = vec![]; | ||
258 | for local_module_id in module_ids_to_process.drain(..) { | ||
259 | for (name, namespace_data) in | ||
260 | crate_def_map[local_module_id].scope.entries_without_primitives() | ||
261 | { | ||
262 | let found_a_match = &name.to_string() == name_to_import; | ||
263 | vec![namespace_data.types, namespace_data.values] | ||
264 | .into_iter() | ||
265 | .filter_map(std::convert::identity) | ||
266 | .for_each(|(module_def_id, _)| { | ||
267 | if found_a_match { | ||
268 | findings.push(module_def_id.into()); | ||
269 | } | ||
270 | if let hir::ModuleDefId::ModuleId(module_id) = module_def_id { | ||
271 | more_ids_to_process.push(module_id.local_id); | ||
272 | } | ||
273 | }); | ||
274 | } | ||
275 | } | ||
276 | module_ids_to_process = more_ids_to_process; | ||
277 | } | ||
278 | |||
279 | findings | ||
280 | } | ||
281 | } | ||
234 | 282 | ||
235 | pub(crate) fn check_assist( | 283 | pub(crate) fn check_assist( |
236 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, | 284 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
@@ -262,16 +310,19 @@ mod helpers { | |||
262 | 310 | ||
263 | pub(crate) fn check_assist_with_imports_locator<F: ImportsLocator>( | 311 | pub(crate) fn check_assist_with_imports_locator<F: ImportsLocator>( |
264 | assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>, | 312 | assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>, |
265 | imports_locator: &mut F, | 313 | imports_locator_provider: fn(db: Arc<TestDB>, file_id: FileId) -> F, |
266 | before: &str, | 314 | before: &str, |
267 | after: &str, | 315 | after: &str, |
268 | ) { | 316 | ) { |
269 | let (before_cursor_pos, before) = extract_offset(before); | 317 | let (before_cursor_pos, before) = extract_offset(before); |
270 | let (db, file_id) = TestDB::with_single_file(&before); | 318 | let (db, file_id) = TestDB::with_single_file(&before); |
319 | let db = Arc::new(db); | ||
320 | let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id); | ||
271 | let frange = | 321 | let frange = |
272 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 322 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
273 | let assist = AssistCtx::with_ctx(&db, frange, true, |ctx| assist(ctx, imports_locator)) | 323 | let assist = |
274 | .expect("code action is not applicable"); | 324 | AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator)) |
325 | .expect("code action is not applicable"); | ||
275 | let action = match assist { | 326 | let action = match assist { |
276 | Assist::Unresolved { .. } => unreachable!(), | 327 | Assist::Unresolved { .. } => unreachable!(), |
277 | Assist::Resolved { assist } => assist.get_first_action(), | 328 | Assist::Resolved { assist } => assist.get_first_action(), |
@@ -364,14 +415,17 @@ mod helpers { | |||
364 | 415 | ||
365 | pub(crate) fn check_assist_with_imports_locator_not_applicable<F: ImportsLocator>( | 416 | pub(crate) fn check_assist_with_imports_locator_not_applicable<F: ImportsLocator>( |
366 | assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>, | 417 | assist: fn(AssistCtx<TestDB>, &mut F) -> Option<Assist>, |
367 | imports_locator: &mut F, | 418 | imports_locator_provider: fn(db: Arc<TestDB>, file_id: FileId) -> F, |
368 | before: &str, | 419 | before: &str, |
369 | ) { | 420 | ) { |
370 | let (before_cursor_pos, before) = extract_offset(before); | 421 | let (before_cursor_pos, before) = extract_offset(before); |
371 | let (db, file_id) = TestDB::with_single_file(&before); | 422 | let (db, file_id) = TestDB::with_single_file(&before); |
423 | let db = Arc::new(db); | ||
424 | let mut imports_locator = imports_locator_provider(Arc::clone(&db), file_id); | ||
372 | let frange = | 425 | let frange = |
373 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 426 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
374 | let assist = AssistCtx::with_ctx(&db, frange, true, |ctx| assist(ctx, imports_locator)); | 427 | let assist = |
428 | AssistCtx::with_ctx(db.as_ref(), frange, true, |ctx| assist(ctx, &mut imports_locator)); | ||
375 | assert!(assist.is_none()); | 429 | assert!(assist.is_none()); |
376 | } | 430 | } |
377 | 431 | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 21b0553be..2cfeaba72 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -56,6 +56,7 @@ pub use hir_def::{ | |||
56 | nameres::ModuleSource, | 56 | nameres::ModuleSource, |
57 | path::{ModPath, Path, PathKind}, | 57 | path::{ModPath, Path, PathKind}, |
58 | type_ref::Mutability, | 58 | type_ref::Mutability, |
59 | ModuleDefId, | ||
59 | }; | 60 | }; |
60 | pub use hir_expand::{ | 61 | pub use hir_expand::{ |
61 | name::{AsName, Name}, | 62 | name::{AsName, Name}, |