diff options
author | Aleksey Kladov <[email protected]> | 2018-12-09 10:49:54 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-12-09 10:49:54 +0000 |
commit | 7784c7a701ba944decf671f80dea581d68667663 (patch) | |
tree | 548400065966f715ae203e6f6e0fcfd9f12e4470 | |
parent | e89da32bb7cf7388946964e1e34df722527d0838 (diff) |
resolve extern crates propertly
-rw-r--r-- | crates/ra_db/src/mock.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres/tests.rs | 37 |
4 files changed, 98 insertions, 51 deletions
diff --git a/crates/ra_db/src/mock.rs b/crates/ra_db/src/mock.rs index 2840f9655..2f7551597 100644 --- a/crates/ra_db/src/mock.rs +++ b/crates/ra_db/src/mock.rs | |||
@@ -5,7 +5,7 @@ use relative_path::{RelativePath, RelativePathBuf}; | |||
5 | 5 | ||
6 | use crate::{FileId, FileResolver, SourceRoot, FileResolverImp}; | 6 | use crate::{FileId, FileResolver, SourceRoot, FileResolverImp}; |
7 | 7 | ||
8 | #[derive(Default, Debug)] | 8 | #[derive(Default, Debug, Clone)] |
9 | pub struct FileMap(Vec<(FileId, RelativePathBuf)>); | 9 | pub struct FileMap(Vec<(FileId, RelativePathBuf)>); |
10 | 10 | ||
11 | impl FileMap { | 11 | impl FileMap { |
@@ -28,6 +28,11 @@ impl FileMap { | |||
28 | self.iter().map(|(id, _)| id).collect() | 28 | self.iter().map(|(id, _)| id).collect() |
29 | } | 29 | } |
30 | 30 | ||
31 | pub fn file_id(&self, path: &str) -> FileId { | ||
32 | assert!(path.starts_with('/')); | ||
33 | self.iter().find(|(_, p)| p == &path[1..]).unwrap().0 | ||
34 | } | ||
35 | |||
31 | fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { | 36 | fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a { |
32 | self.0 | 37 | self.0 |
33 | .iter() | 38 | .iter() |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index e855df11d..b7193c4f3 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -2,7 +2,7 @@ use std::sync::Arc; | |||
2 | 2 | ||
3 | use parking_lot::Mutex; | 3 | use parking_lot::Mutex; |
4 | use salsa::{self, Database}; | 4 | use salsa::{self, Database}; |
5 | use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE}; | 5 | use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE, CrateGraph}; |
6 | use relative_path::RelativePathBuf; | 6 | use relative_path::RelativePathBuf; |
7 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | 7 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; |
8 | 8 | ||
@@ -16,7 +16,24 @@ pub(crate) struct MockDatabase { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | impl MockDatabase { | 18 | impl MockDatabase { |
19 | pub(crate) fn with_files(fixture: &str) -> (MockDatabase, FileMap) { | ||
20 | let (db, file_map, position) = MockDatabase::from_fixture(fixture); | ||
21 | assert!(position.is_none()); | ||
22 | (db, file_map) | ||
23 | } | ||
24 | |||
19 | pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { | 25 | pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { |
26 | let (db, _, position) = MockDatabase::from_fixture(fixture); | ||
27 | let position = position.expect("expected a marker ( <|> )"); | ||
28 | (db, position) | ||
29 | } | ||
30 | |||
31 | pub(crate) fn set_crate_graph(&mut self, crate_graph: CrateGraph) { | ||
32 | self.query_mut(ra_db::CrateGraphQuery) | ||
33 | .set((), Arc::new(crate_graph)); | ||
34 | } | ||
35 | |||
36 | fn from_fixture(fixture: &str) -> (MockDatabase, FileMap, Option<FilePosition>) { | ||
20 | let mut db = MockDatabase::default(); | 37 | let mut db = MockDatabase::default(); |
21 | 38 | ||
22 | let mut position = None; | 39 | let mut position = None; |
@@ -32,11 +49,10 @@ impl MockDatabase { | |||
32 | db.add_file(&mut file_map, &entry.meta, &entry.text); | 49 | db.add_file(&mut file_map, &entry.meta, &entry.text); |
33 | } | 50 | } |
34 | } | 51 | } |
35 | let position = position.expect("expected a marker (<|>)"); | 52 | let source_root = file_map.clone().into_source_root(); |
36 | let source_root = file_map.into_source_root(); | ||
37 | db.query_mut(ra_db::SourceRootQuery) | 53 | db.query_mut(ra_db::SourceRootQuery) |
38 | .set(WORKSPACE, Arc::new(source_root)); | 54 | .set(WORKSPACE, Arc::new(source_root)); |
39 | (db, position) | 55 | (db, file_map, position) |
40 | } | 56 | } |
41 | 57 | ||
42 | fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { | 58 | fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { |
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 5e4bb7669..9afeade9e 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -228,7 +228,7 @@ where | |||
228 | 228 | ||
229 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { | 229 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { |
230 | for (&module_id, items) in self.input.iter() { | 230 | for (&module_id, items) in self.input.iter() { |
231 | self.populate_module(module_id, items) | 231 | self.populate_module(module_id, items)?; |
232 | } | 232 | } |
233 | 233 | ||
234 | for &module_id in self.input.keys() { | 234 | for &module_id in self.input.keys() { |
@@ -238,11 +238,25 @@ where | |||
238 | Ok(self.result) | 238 | Ok(self.result) |
239 | } | 239 | } |
240 | 240 | ||
241 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { | 241 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) -> Cancelable<()> { |
242 | let file_id = module_id.source(&self.module_tree).file_id(); | 242 | let file_id = module_id.source(&self.module_tree).file_id(); |
243 | 243 | ||
244 | let mut module_items = ModuleScope::default(); | 244 | let mut module_items = ModuleScope::default(); |
245 | 245 | ||
246 | // Populate extern crates prelude | ||
247 | { | ||
248 | let root_id = module_id.crate_root(&self.module_tree); | ||
249 | let file_id = root_id.source(&self.module_tree).file_id(); | ||
250 | let crate_graph = self.db.crate_graph(); | ||
251 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id) { | ||
252 | let krate = Crate::new(crate_id); | ||
253 | for dep in krate.dependencies(self.db) { | ||
254 | if let Some(module) = dep.krate.root_module(self.db)? { | ||
255 | self.add_module_item(&mut module_items, dep.name, module.module_id); | ||
256 | } | ||
257 | } | ||
258 | }; | ||
259 | } | ||
246 | for import in input.imports.iter() { | 260 | for import in input.imports.iter() { |
247 | if let Some(name) = import.path.segments.iter().last() { | 261 | if let Some(name) = import.path.segments.iter().last() { |
248 | if let ImportKind::Named(import) = import.kind { | 262 | if let ImportKind::Named(import) = import.kind { |
@@ -256,10 +270,9 @@ where | |||
256 | } | 270 | } |
257 | } | 271 | } |
258 | } | 272 | } |
259 | 273 | // Populate explicitelly declared items, except modules | |
260 | for item in input.items.iter() { | 274 | for item in input.items.iter() { |
261 | if item.kind == MODULE { | 275 | if item.kind == MODULE { |
262 | // handle submodules separatelly | ||
263 | continue; | 276 | continue; |
264 | } | 277 | } |
265 | let def_loc = DefLoc { | 278 | let def_loc = DefLoc { |
@@ -279,22 +292,28 @@ where | |||
279 | module_items.items.insert(item.name.clone(), resolution); | 292 | module_items.items.insert(item.name.clone(), resolution); |
280 | } | 293 | } |
281 | 294 | ||
295 | // Populate modules | ||
282 | for (name, module_id) in module_id.children(&self.module_tree) { | 296 | for (name, module_id) in module_id.children(&self.module_tree) { |
283 | let def_loc = DefLoc { | 297 | self.add_module_item(&mut module_items, name, module_id); |
284 | kind: DefKind::Module, | ||
285 | source_root_id: self.source_root, | ||
286 | module_id, | ||
287 | source_item_id: module_id.source(&self.module_tree).0, | ||
288 | }; | ||
289 | let def_id = def_loc.id(self.db); | ||
290 | let resolution = Resolution { | ||
291 | def_id: Some(def_id), | ||
292 | import: None, | ||
293 | }; | ||
294 | module_items.items.insert(name, resolution); | ||
295 | } | 298 | } |
296 | 299 | ||
297 | self.result.per_module.insert(module_id, module_items); | 300 | self.result.per_module.insert(module_id, module_items); |
301 | Ok(()) | ||
302 | } | ||
303 | |||
304 | fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, module_id: ModuleId) { | ||
305 | let def_loc = DefLoc { | ||
306 | kind: DefKind::Module, | ||
307 | source_root_id: self.source_root, | ||
308 | module_id, | ||
309 | source_item_id: module_id.source(&self.module_tree).0, | ||
310 | }; | ||
311 | let def_id = def_loc.id(self.db); | ||
312 | let resolution = Resolution { | ||
313 | def_id: Some(def_id), | ||
314 | import: None, | ||
315 | }; | ||
316 | module_items.items.insert(name, resolution); | ||
298 | } | 317 | } |
299 | 318 | ||
300 | fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { | 319 | fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { |
@@ -309,35 +328,9 @@ where | |||
309 | ImportKind::Glob => return Ok(()), | 328 | ImportKind::Glob => return Ok(()), |
310 | ImportKind::Named(ptr) => ptr, | 329 | ImportKind::Named(ptr) => ptr, |
311 | }; | 330 | }; |
312 | let mut segments = import.path.segments.iter().enumerate(); | ||
313 | 331 | ||
314 | let mut curr = match import.path.kind { | 332 | let mut curr = match import.path.kind { |
315 | PathKind::Plain => { | 333 | PathKind::Plain | PathKind::Self_ => module_id, |
316 | let root_id = module_id.crate_root(&self.module_tree); | ||
317 | let file_id = root_id.source(&self.module_tree).file_id(); | ||
318 | let crate_graph = self.db.crate_graph(); | ||
319 | let crate_id = match crate_graph.crate_id_for_crate_root(file_id) { | ||
320 | None => return Ok(()), | ||
321 | Some(it) => it, | ||
322 | }; | ||
323 | let krate = Crate::new(crate_id); | ||
324 | let crate_name = match segments.next() { | ||
325 | None => return Ok(()), | ||
326 | Some((_, it)) => it, | ||
327 | }; | ||
328 | match krate | ||
329 | .dependencies(self.db) | ||
330 | .into_iter() | ||
331 | .find(|it| &it.name == crate_name) | ||
332 | { | ||
333 | None => return Ok(()), | ||
334 | Some(dep) => match dep.krate.root_module(self.db)? { | ||
335 | None => return Ok(()), | ||
336 | Some(it) => it.module_id, | ||
337 | }, | ||
338 | } | ||
339 | } | ||
340 | PathKind::Self_ => module_id, | ||
341 | PathKind::Super => { | 334 | PathKind::Super => { |
342 | match module_id.parent(&self.module_tree) { | 335 | match module_id.parent(&self.module_tree) { |
343 | Some(it) => it, | 336 | Some(it) => it, |
@@ -348,7 +341,7 @@ where | |||
348 | PathKind::Crate => module_id.crate_root(&self.module_tree), | 341 | PathKind::Crate => module_id.crate_root(&self.module_tree), |
349 | }; | 342 | }; |
350 | 343 | ||
351 | for (i, name) in segments { | 344 | for (i, name) in import.path.segments.iter().enumerate() { |
352 | let is_last = i == import.path.segments.len() - 1; | 345 | let is_last = i == import.path.segments.len() - 1; |
353 | 346 | ||
354 | let def_id = match self.result.per_module[&curr].items.get(name) { | 347 | let def_id = match self.result.per_module[&curr].items.get(name) { |
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs index 060683e27..9ddc32dcd 100644 --- a/crates/ra_hir/src/module/nameres/tests.rs +++ b/crates/ra_hir/src/module/nameres/tests.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use salsa::Database; | 3 | use salsa::Database; |
4 | use ra_db::FilesDatabase; | 4 | use ra_db::{FilesDatabase, CrateGraph}; |
5 | use ra_syntax::SmolStr; | 5 | use ra_syntax::SmolStr; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
@@ -21,7 +21,7 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn test_item_map() { | 24 | fn item_map_smoke_test() { |
25 | let (item_map, module_id) = item_map( | 25 | let (item_map, module_id) = item_map( |
26 | " | 26 | " |
27 | //- /lib.rs | 27 | //- /lib.rs |
@@ -43,6 +43,39 @@ fn test_item_map() { | |||
43 | } | 43 | } |
44 | 44 | ||
45 | #[test] | 45 | #[test] |
46 | fn item_map_across_crates() { | ||
47 | let (mut db, files) = MockDatabase::with_files( | ||
48 | " | ||
49 | //- /main.rs | ||
50 | use test_crate::Baz; | ||
51 | |||
52 | //- /lib.rs | ||
53 | pub struct Baz; | ||
54 | ", | ||
55 | ); | ||
56 | let main_id = files.file_id("/main.rs"); | ||
57 | let lib_id = files.file_id("/lib.rs"); | ||
58 | |||
59 | let mut crate_graph = CrateGraph::default(); | ||
60 | let main_crate = crate_graph.add_crate_root(main_id); | ||
61 | let lib_crate = crate_graph.add_crate_root(lib_id); | ||
62 | crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate); | ||
63 | |||
64 | db.set_crate_graph(crate_graph); | ||
65 | |||
66 | let source_root = db.file_source_root(main_id); | ||
67 | let module = hir::source_binder::module_from_file_id(&db, main_id) | ||
68 | .unwrap() | ||
69 | .unwrap(); | ||
70 | let module_id = module.module_id; | ||
71 | let item_map = db.item_map(source_root).unwrap(); | ||
72 | |||
73 | let name = SmolStr::from("Baz"); | ||
74 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
75 | assert!(resolution.def_id.is_some()); | ||
76 | } | ||
77 | |||
78 | #[test] | ||
46 | fn typing_inside_a_function_should_not_invalidate_item_map() { | 79 | fn typing_inside_a_function_should_not_invalidate_item_map() { |
47 | let (mut db, pos) = MockDatabase::with_position( | 80 | let (mut db, pos) = MockDatabase::with_position( |
48 | " | 81 | " |