aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/mock.rs46
-rw-r--r--crates/ra_hir/src/module/imp.rs50
-rw-r--r--crates/ra_hir/src/module/nameres.rs51
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs7
5 files changed, 97 insertions, 58 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 1b9e148b2..61650cee9 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -5,6 +5,7 @@ version = "0.1.0"
5authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
6 6
7[dependencies] 7[dependencies]
8arrayvec = "0.4.9"
8log = "0.4.5" 9log = "0.4.5"
9relative-path = "0.4.0" 10relative-path = "0.4.0"
10salsa = "0.8.0" 11salsa = "0.8.0"
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
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, CrateGraph}; 5use ra_db::{LocationIntener, BaseDatabase, FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId};
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
9use crate::{db, DefId, DefLoc}; 9use crate::{db, DefId, DefLoc};
10 10
11const WORKSPACE: SourceRootId = SourceRootId(0);
12
11#[derive(Debug)] 13#[derive(Debug)]
12pub(crate) struct MockDatabase { 14pub(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
18impl MockDatabase { 20impl 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};
7use relative_path::RelativePathBuf; 7use relative_path::{RelativePathBuf, RelativePath};
8use rustc_hash::{FxHashMap, FxHashSet}; 8use rustc_hash::{FxHashMap, FxHashSet};
9use ra_db::{SourceRoot, SourceRootId, FileResolverImp, Cancelable, FileId,}; 9use arrayvec::ArrayVec;
10use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
10 11
11use crate::{ 12use 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
155fn resolve_submodule( 155fn 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)]
41pub struct ItemMap { 42pub 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;
3use salsa::Database; 3use salsa::Database;
4use ra_db::{FilesDatabase, CrateGraph}; 4use ra_db::{FilesDatabase, CrateGraph};
5use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
6use relative_path::RelativePath;
6 7
7use crate::{ 8use crate::{
8 self as hir, 9 self as hir,
@@ -44,7 +45,7 @@ fn item_map_smoke_test() {
44 45
45#[test] 46#[test]
46fn item_map_across_crates() { 47fn 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);