aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs144
-rw-r--r--crates/ra_assists/src/lib.rs66
-rw-r--r--crates/ra_hir/src/lib.rs1
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)]
228mod helpers { 228mod 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};
60pub use hir_expand::{ 61pub use hir_expand::{
61 name::{AsName, Name}, 62 name::{AsName, Name},