aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-12-09 10:49:54 +0000
committerAleksey Kladov <[email protected]>2018-12-09 10:49:54 +0000
commit7784c7a701ba944decf671f80dea581d68667663 (patch)
tree548400065966f715ae203e6f6e0fcfd9f12e4470
parente89da32bb7cf7388946964e1e34df722527d0838 (diff)
resolve extern crates propertly
-rw-r--r--crates/ra_db/src/mock.rs7
-rw-r--r--crates/ra_hir/src/mock.rs24
-rw-r--r--crates/ra_hir/src/module/nameres.rs81
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs37
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
6use crate::{FileId, FileResolver, SourceRoot, FileResolverImp}; 6use crate::{FileId, FileResolver, SourceRoot, FileResolverImp};
7 7
8#[derive(Default, Debug)] 8#[derive(Default, Debug, Clone)]
9pub struct FileMap(Vec<(FileId, RelativePathBuf)>); 9pub struct FileMap(Vec<(FileId, RelativePathBuf)>);
10 10
11impl FileMap { 11impl 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
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use salsa::{self, Database}; 4use salsa::{self, Database};
5use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE}; 5use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE, CrateGraph};
6use relative_path::RelativePathBuf; 6use relative_path::RelativePathBuf;
7use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 7use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
8 8
@@ -16,7 +16,24 @@ pub(crate) struct MockDatabase {
16} 16}
17 17
18impl MockDatabase { 18impl 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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use salsa::Database; 3use salsa::Database;
4use ra_db::FilesDatabase; 4use ra_db::{FilesDatabase, CrateGraph};
5use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
6 6
7use crate::{ 7use crate::{
@@ -21,7 +21,7 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
21} 21}
22 22
23#[test] 23#[test]
24fn test_item_map() { 24fn 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]
46fn 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]
46fn typing_inside_a_function_should_not_invalidate_item_map() { 79fn 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 "