diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/mock.rs | 46 | ||||
-rw-r--r-- | crates/ra_hir/src/module/imp.rs | 50 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 51 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres/tests.rs | 7 |
4 files changed, 96 insertions, 58 deletions
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index b7193c4f3..9423e6571 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -2,12 +2,14 @@ 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, CrateGraph}; | 5 | use ra_db::{LocationIntener, BaseDatabase, FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId}; |
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 | ||
9 | use crate::{db, DefId, DefLoc}; | 9 | use crate::{db, DefId, DefLoc}; |
10 | 10 | ||
11 | const WORKSPACE: SourceRootId = SourceRootId(0); | ||
12 | |||
11 | #[derive(Debug)] | 13 | #[derive(Debug)] |
12 | pub(crate) struct MockDatabase { | 14 | pub(crate) struct MockDatabase { |
13 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, | 15 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, |
@@ -16,10 +18,10 @@ pub(crate) struct MockDatabase { | |||
16 | } | 18 | } |
17 | 19 | ||
18 | impl MockDatabase { | 20 | impl MockDatabase { |
19 | pub(crate) fn with_files(fixture: &str) -> (MockDatabase, FileMap) { | 21 | pub(crate) fn with_files(fixture: &str) -> (MockDatabase, SourceRoot) { |
20 | let (db, file_map, position) = MockDatabase::from_fixture(fixture); | 22 | let (db, source_root, position) = MockDatabase::from_fixture(fixture); |
21 | assert!(position.is_none()); | 23 | assert!(position.is_none()); |
22 | (db, file_map) | 24 | (db, source_root) |
23 | } | 25 | } |
24 | 26 | ||
25 | pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { | 27 | pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { |
@@ -33,48 +35,50 @@ impl MockDatabase { | |||
33 | .set((), Arc::new(crate_graph)); | 35 | .set((), Arc::new(crate_graph)); |
34 | } | 36 | } |
35 | 37 | ||
36 | fn from_fixture(fixture: &str) -> (MockDatabase, FileMap, Option<FilePosition>) { | 38 | fn from_fixture(fixture: &str) -> (MockDatabase, SourceRoot, Option<FilePosition>) { |
37 | let mut db = MockDatabase::default(); | 39 | let mut db = MockDatabase::default(); |
38 | 40 | ||
39 | let mut position = None; | 41 | let mut position = None; |
40 | let mut file_map = FileMap::default(); | 42 | let mut source_root = SourceRoot::default(); |
41 | for entry in parse_fixture(fixture) { | 43 | for entry in parse_fixture(fixture) { |
42 | if entry.text.contains(CURSOR_MARKER) { | 44 | if entry.text.contains(CURSOR_MARKER) { |
43 | assert!( | 45 | assert!( |
44 | position.is_none(), | 46 | position.is_none(), |
45 | "only one marker (<|>) per fixture is allowed" | 47 | "only one marker (<|>) per fixture is allowed" |
46 | ); | 48 | ); |
47 | position = Some(db.add_file_with_position(&mut file_map, &entry.meta, &entry.text)); | 49 | position = |
50 | Some(db.add_file_with_position(&mut source_root, &entry.meta, &entry.text)); | ||
48 | } else { | 51 | } else { |
49 | db.add_file(&mut file_map, &entry.meta, &entry.text); | 52 | db.add_file(&mut source_root, &entry.meta, &entry.text); |
50 | } | 53 | } |
51 | } | 54 | } |
52 | let source_root = file_map.clone().into_source_root(); | ||
53 | db.query_mut(ra_db::SourceRootQuery) | 55 | db.query_mut(ra_db::SourceRootQuery) |
54 | .set(WORKSPACE, Arc::new(source_root)); | 56 | .set(WORKSPACE, Arc::new(source_root.clone())); |
55 | (db, file_map, position) | 57 | (db, source_root, position) |
56 | } | 58 | } |
57 | 59 | ||
58 | fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { | 60 | fn add_file(&mut self, source_root: &mut SourceRoot, path: &str, text: &str) -> FileId { |
59 | assert!(path.starts_with('/')); | 61 | assert!(path.starts_with('/')); |
60 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | 62 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); |
61 | 63 | let file_id = FileId(source_root.files.len() as u32); | |
62 | let file_id = file_map.add(path); | ||
63 | let text = Arc::new(text.to_string()); | 64 | let text = Arc::new(text.to_string()); |
64 | self.query_mut(ra_db::FileTextQuery).set(file_id, text); | 65 | self.query_mut(ra_db::FileTextQuery).set(file_id, text); |
66 | self.query_mut(ra_db::FileRelativePathQuery) | ||
67 | .set(file_id, path.clone()); | ||
65 | self.query_mut(ra_db::FileSourceRootQuery) | 68 | self.query_mut(ra_db::FileSourceRootQuery) |
66 | .set(file_id, WORKSPACE); | 69 | .set(file_id, WORKSPACE); |
70 | source_root.files.insert(path, file_id); | ||
67 | file_id | 71 | file_id |
68 | } | 72 | } |
69 | 73 | ||
70 | fn add_file_with_position( | 74 | fn add_file_with_position( |
71 | &mut self, | 75 | &mut self, |
72 | file_map: &mut FileMap, | 76 | source_root: &mut SourceRoot, |
73 | path: &str, | 77 | path: &str, |
74 | text: &str, | 78 | text: &str, |
75 | ) -> FilePosition { | 79 | ) -> FilePosition { |
76 | let (offset, text) = extract_offset(text); | 80 | let (offset, text) = extract_offset(text); |
77 | let file_id = self.add_file(file_map, path, &text); | 81 | let file_id = self.add_file(source_root, path, &text); |
78 | FilePosition { file_id, offset } | 82 | FilePosition { file_id, offset } |
79 | } | 83 | } |
80 | } | 84 | } |
@@ -104,11 +108,11 @@ impl Default for MockDatabase { | |||
104 | runtime: salsa::Runtime::default(), | 108 | runtime: salsa::Runtime::default(), |
105 | id_maps: Default::default(), | 109 | id_maps: Default::default(), |
106 | }; | 110 | }; |
107 | db.query_mut(ra_db::SourceRootQuery) | ||
108 | .set(ra_db::WORKSPACE, Default::default()); | ||
109 | db.query_mut(ra_db::CrateGraphQuery) | 111 | db.query_mut(ra_db::CrateGraphQuery) |
110 | .set((), Default::default()); | 112 | .set((), Default::default()); |
111 | db.query_mut(ra_db::LibrariesQuery) | 113 | db.query_mut(ra_db::LocalRootsQuery) |
114 | .set((), Default::default()); | ||
115 | db.query_mut(ra_db::LibraryRootsQuery) | ||
112 | .set((), Default::default()); | 116 | .set((), Default::default()); |
113 | db | 117 | db |
114 | } | 118 | } |
@@ -158,9 +162,11 @@ salsa::database_storage! { | |||
158 | pub(crate) struct MockDatabaseStorage for MockDatabase { | 162 | pub(crate) struct MockDatabaseStorage for MockDatabase { |
159 | impl ra_db::FilesDatabase { | 163 | impl ra_db::FilesDatabase { |
160 | fn file_text() for ra_db::FileTextQuery; | 164 | fn file_text() for ra_db::FileTextQuery; |
165 | fn file_relative_path() for ra_db::FileRelativePathQuery; | ||
161 | fn file_source_root() for ra_db::FileSourceRootQuery; | 166 | fn file_source_root() for ra_db::FileSourceRootQuery; |
162 | fn source_root() for ra_db::SourceRootQuery; | 167 | fn source_root() for ra_db::SourceRootQuery; |
163 | fn libraries() for ra_db::LibrariesQuery; | 168 | fn local_roots() for ra_db::LocalRootsQuery; |
169 | fn library_roots() for ra_db::LibraryRootsQuery; | ||
164 | fn crate_graph() for ra_db::CrateGraphQuery; | 170 | fn crate_graph() for ra_db::CrateGraphQuery; |
165 | } | 171 | } |
166 | impl ra_db::SyntaxDatabase { | 172 | impl ra_db::SyntaxDatabase { |
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs index 4a19842c4..f3a346152 100644 --- a/crates/ra_hir/src/module/imp.rs +++ b/crates/ra_hir/src/module/imp.rs | |||
@@ -4,9 +4,10 @@ use ra_syntax::{ | |||
4 | ast::{self, NameOwner}, | 4 | ast::{self, NameOwner}, |
5 | SmolStr, | 5 | SmolStr, |
6 | }; | 6 | }; |
7 | use relative_path::RelativePathBuf; | 7 | use relative_path::{RelativePathBuf, RelativePath}; |
8 | use rustc_hash::{FxHashMap, FxHashSet}; | 8 | use rustc_hash::{FxHashMap, FxHashSet}; |
9 | use ra_db::{SourceRoot, SourceRootId, FileResolverImp, Cancelable, FileId,}; | 9 | use arrayvec::ArrayVec; |
10 | use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; | ||
10 | 11 | ||
11 | use crate::{ | 12 | use crate::{ |
12 | HirDatabase, | 13 | HirDatabase, |
@@ -65,7 +66,7 @@ fn create_module_tree<'a>( | |||
65 | let mut visited = FxHashSet::default(); | 66 | let mut visited = FxHashSet::default(); |
66 | 67 | ||
67 | let source_root = db.source_root(source_root); | 68 | let source_root = db.source_root(source_root); |
68 | for &file_id in source_root.files.iter() { | 69 | for &file_id in source_root.files.values() { |
69 | let source = ModuleSource::new_file(file_id); | 70 | let source = ModuleSource::new_file(file_id); |
70 | if visited.contains(&source) { | 71 | if visited.contains(&source) { |
71 | continue; // TODO: use explicit crate_roots here | 72 | continue; // TODO: use explicit crate_roots here |
@@ -110,8 +111,7 @@ fn build_subtree( | |||
110 | 111 | ||
111 | let (points_to, problem) = match sub { | 112 | let (points_to, problem) = match sub { |
112 | Submodule::Declaration(name) => { | 113 | Submodule::Declaration(name) => { |
113 | let (points_to, problem) = | 114 | let (points_to, problem) = resolve_submodule(db, source, &name); |
114 | resolve_submodule(source, &name, &source_root.file_resolver); | ||
115 | let points_to = points_to | 115 | let points_to = points_to |
116 | .into_iter() | 116 | .into_iter() |
117 | .map(|file_id| match roots.remove(&file_id) { | 117 | .map(|file_id| match roots.remove(&file_id) { |
@@ -153,34 +153,42 @@ fn build_subtree( | |||
153 | } | 153 | } |
154 | 154 | ||
155 | fn resolve_submodule( | 155 | fn resolve_submodule( |
156 | db: &impl HirDatabase, | ||
156 | source: ModuleSource, | 157 | source: ModuleSource, |
157 | name: &SmolStr, | 158 | name: &SmolStr, |
158 | file_resolver: &FileResolverImp, | ||
159 | ) -> (Vec<FileId>, Option<Problem>) { | 159 | ) -> (Vec<FileId>, Option<Problem>) { |
160 | // TODO: handle submodules of inline modules properly | 160 | // FIXME: handle submodules of inline modules properly |
161 | let file_id = source.file_id(); | 161 | let file_id = source.file_id(); |
162 | let mod_name = file_resolver.file_stem(file_id); | 162 | let source_root_id = db.file_source_root(file_id); |
163 | let path = db.file_relative_path(file_id); | ||
164 | let root = RelativePathBuf::default(); | ||
165 | let dir_path = path.parent().unwrap_or(&root); | ||
166 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
163 | let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; | 167 | let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; |
164 | 168 | ||
165 | let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); | 169 | let file_mod = dir_path.join(format!("{}.rs", name)); |
166 | let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); | 170 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); |
167 | let file_dir_mod = RelativePathBuf::from(format!("../{}/{}.rs", mod_name, name)); | 171 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); |
168 | let tmp1; | 172 | let mut candidates = ArrayVec::<[_; 2]>::new(); |
169 | let tmp2; | 173 | if is_dir_owner { |
170 | let candidates = if is_dir_owner { | 174 | candidates.push(file_mod.clone()); |
171 | tmp1 = [&file_mod, &dir_mod]; | 175 | candidates.push(dir_mod); |
172 | tmp1.iter() | ||
173 | } else { | 176 | } else { |
174 | tmp2 = [&file_dir_mod]; | 177 | candidates.push(file_dir_mod.clone()); |
175 | tmp2.iter() | ||
176 | }; | 178 | }; |
177 | 179 | let sr = db.source_root(source_root_id); | |
178 | let points_to = candidates | 180 | let points_to = candidates |
179 | .filter_map(|path| file_resolver.resolve(file_id, path)) | 181 | .into_iter() |
182 | .filter_map(|path| sr.files.get(&path)) | ||
183 | .map(|&it| it) | ||
180 | .collect::<Vec<_>>(); | 184 | .collect::<Vec<_>>(); |
181 | let problem = if points_to.is_empty() { | 185 | let problem = if points_to.is_empty() { |
182 | Some(Problem::UnresolvedModule { | 186 | Some(Problem::UnresolvedModule { |
183 | candidate: if is_dir_owner { file_mod } else { file_dir_mod }, | 187 | candidate: RelativePath::new("../").join(&if is_dir_owner { |
188 | file_mod | ||
189 | } else { | ||
190 | file_dir_mod | ||
191 | }), | ||
184 | }) | 192 | }) |
185 | } else { | 193 | } else { |
186 | None | 194 | None |
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 5540b827f..f44abc730 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -32,11 +32,12 @@ use crate::{ | |||
32 | SourceItemId, SourceFileItemId, SourceFileItems, | 32 | SourceItemId, SourceFileItemId, SourceFileItems, |
33 | Path, PathKind, | 33 | Path, PathKind, |
34 | HirDatabase, Crate, | 34 | HirDatabase, Crate, |
35 | module::{ModuleId, ModuleTree}, | 35 | module::{Module, ModuleId, ModuleTree}, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | /// Item map is the result of the name resolution. Item map contains, for each | 38 | /// Item map is the result of the name resolution. Item map contains, for each |
39 | /// module, the set of visible items. | 39 | /// module, the set of visible items. |
40 | // FIXME: currenty we compute item map per source-root. We should do it per crate instead. | ||
40 | #[derive(Default, Debug, PartialEq, Eq)] | 41 | #[derive(Default, Debug, PartialEq, Eq)] |
41 | pub struct ItemMap { | 42 | pub struct ItemMap { |
42 | pub per_module: FxHashMap<ModuleId, ModuleScope>, | 43 | pub per_module: FxHashMap<ModuleId, ModuleScope>, |
@@ -252,7 +253,8 @@ where | |||
252 | let krate = Crate::new(crate_id); | 253 | let krate = Crate::new(crate_id); |
253 | for dep in krate.dependencies(self.db) { | 254 | for dep in krate.dependencies(self.db) { |
254 | if let Some(module) = dep.krate.root_module(self.db)? { | 255 | if let Some(module) = dep.krate.root_module(self.db)? { |
255 | self.add_module_item(&mut module_items, dep.name, module.module_id); | 256 | let def_id = module.def_id(self.db); |
257 | self.add_module_item(&mut module_items, dep.name, def_id); | ||
256 | } | 258 | } |
257 | } | 259 | } |
258 | }; | 260 | }; |
@@ -294,21 +296,21 @@ where | |||
294 | 296 | ||
295 | // Populate modules | 297 | // Populate modules |
296 | for (name, module_id) in module_id.children(&self.module_tree) { | 298 | for (name, module_id) in module_id.children(&self.module_tree) { |
297 | self.add_module_item(&mut module_items, name, module_id); | 299 | let def_loc = DefLoc { |
300 | kind: DefKind::Module, | ||
301 | source_root_id: self.source_root, | ||
302 | module_id, | ||
303 | source_item_id: module_id.source(&self.module_tree).0, | ||
304 | }; | ||
305 | let def_id = def_loc.id(self.db); | ||
306 | self.add_module_item(&mut module_items, name, def_id); | ||
298 | } | 307 | } |
299 | 308 | ||
300 | self.result.per_module.insert(module_id, module_items); | 309 | self.result.per_module.insert(module_id, module_items); |
301 | Ok(()) | 310 | Ok(()) |
302 | } | 311 | } |
303 | 312 | ||
304 | fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, module_id: ModuleId) { | 313 | fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: DefId) { |
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 { | 314 | let resolution = Resolution { |
313 | def_id: Some(def_id), | 315 | def_id: Some(def_id), |
314 | import: None, | 316 | import: None, |
@@ -329,7 +331,7 @@ where | |||
329 | ImportKind::Named(ptr) => ptr, | 331 | ImportKind::Named(ptr) => ptr, |
330 | }; | 332 | }; |
331 | 333 | ||
332 | let mut curr = match import.path.kind { | 334 | let mut curr: ModuleId = match import.path.kind { |
333 | PathKind::Plain | PathKind::Self_ => module_id, | 335 | PathKind::Plain | PathKind::Self_ => module_id, |
334 | PathKind::Super => { | 336 | PathKind::Super => { |
335 | match module_id.parent(&self.module_tree) { | 337 | match module_id.parent(&self.module_tree) { |
@@ -356,9 +358,30 @@ where | |||
356 | curr = match def_id.loc(self.db) { | 358 | curr = match def_id.loc(self.db) { |
357 | DefLoc { | 359 | DefLoc { |
358 | kind: DefKind::Module, | 360 | kind: DefKind::Module, |
359 | module_id, | 361 | module_id: target_module_id, |
362 | source_root_id, | ||
360 | .. | 363 | .. |
361 | } => module_id, | 364 | } => { |
365 | if source_root_id == self.source_root { | ||
366 | target_module_id | ||
367 | } else { | ||
368 | let module = Module::new(self.db, source_root_id, target_module_id)?; | ||
369 | let path = Path { | ||
370 | segments: import.path.segments[i + 1..].iter().cloned().collect(), | ||
371 | kind: PathKind::Crate, | ||
372 | }; | ||
373 | if let Some(def_id) = module.resolve_path(self.db, path)? { | ||
374 | self.update(module_id, |items| { | ||
375 | let res = Resolution { | ||
376 | def_id: Some(def_id), | ||
377 | import: Some(ptr), | ||
378 | }; | ||
379 | items.items.insert(name.clone(), res); | ||
380 | }) | ||
381 | } | ||
382 | return Ok(()); | ||
383 | } | ||
384 | } | ||
362 | _ => return Ok(()), | 385 | _ => return Ok(()), |
363 | } | 386 | } |
364 | } else { | 387 | } else { |
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs index 9ddc32dcd..9fa9146e3 100644 --- a/crates/ra_hir/src/module/nameres/tests.rs +++ b/crates/ra_hir/src/module/nameres/tests.rs | |||
@@ -3,6 +3,7 @@ use std::sync::Arc; | |||
3 | use salsa::Database; | 3 | use salsa::Database; |
4 | use ra_db::{FilesDatabase, CrateGraph}; | 4 | use ra_db::{FilesDatabase, CrateGraph}; |
5 | use ra_syntax::SmolStr; | 5 | use ra_syntax::SmolStr; |
6 | use relative_path::RelativePath; | ||
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{ |
8 | self as hir, | 9 | self as hir, |
@@ -44,7 +45,7 @@ fn item_map_smoke_test() { | |||
44 | 45 | ||
45 | #[test] | 46 | #[test] |
46 | fn item_map_across_crates() { | 47 | fn item_map_across_crates() { |
47 | let (mut db, files) = MockDatabase::with_files( | 48 | let (mut db, sr) = MockDatabase::with_files( |
48 | " | 49 | " |
49 | //- /main.rs | 50 | //- /main.rs |
50 | use test_crate::Baz; | 51 | use test_crate::Baz; |
@@ -53,8 +54,8 @@ fn item_map_across_crates() { | |||
53 | pub struct Baz; | 54 | pub struct Baz; |
54 | ", | 55 | ", |
55 | ); | 56 | ); |
56 | let main_id = files.file_id("/main.rs"); | 57 | let main_id = sr.files[RelativePath::new("/main.rs")]; |
57 | let lib_id = files.file_id("/lib.rs"); | 58 | let lib_id = sr.files[RelativePath::new("/lib.rs")]; |
58 | 59 | ||
59 | let mut crate_graph = CrateGraph::default(); | 60 | let mut crate_graph = CrateGraph::default(); |
60 | let main_crate = crate_graph.add_crate_root(main_id); | 61 | let main_crate = crate_graph.add_crate_root(main_id); |