aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/mock.rs117
-rw-r--r--crates/ra_hir/src/nameres/tests.rs144
3 files changed, 146 insertions, 116 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index a9cd955cf..8ed8c4bdc 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -18,6 +18,7 @@ macro_rules! impl_froms {
18} 18}
19 19
20pub mod db; 20pub mod db;
21#[macro_use]
21pub mod mock; 22pub mod mock;
22mod query_definitions; 23mod query_definitions;
23mod path; 24mod path;
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 950f89948..5ca870867 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -6,6 +6,7 @@ use ra_db::{
6}; 6};
7use relative_path::RelativePathBuf; 7use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
9use rustc_hash::FxHashMap;
9 10
10use crate::{db, HirInterner}; 11use crate::{db, HirInterner};
11 12
@@ -21,82 +22,125 @@ pub struct MockDatabase {
21 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, 22 events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>,
22 runtime: salsa::Runtime<MockDatabase>, 23 runtime: salsa::Runtime<MockDatabase>,
23 interner: Arc<HirInterner>, 24 interner: Arc<HirInterner>,
24 file_counter: u32, 25 files: FxHashMap<String, FileId>,
25} 26}
26 27
27impl panic::RefUnwindSafe for MockDatabase {} 28impl panic::RefUnwindSafe for MockDatabase {}
28 29
29impl MockDatabase { 30impl MockDatabase {
30 pub fn with_files(fixture: &str) -> (MockDatabase, SourceRoot) { 31 pub fn with_files(fixture: &str) -> MockDatabase {
31 let (db, source_root, position) = MockDatabase::from_fixture(fixture); 32 let (db, position) = MockDatabase::from_fixture(fixture);
32 assert!(position.is_none()); 33 assert!(position.is_none());
33 (db, source_root) 34 db
34 } 35 }
35 36
36 pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) { 37 pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) {
37 let mut db = MockDatabase::default(); 38 let mut db = MockDatabase::default();
38 let mut source_root = SourceRoot::default(); 39 let mut source_root = SourceRoot::default();
39 let file_id = db.add_file(WORKSPACE, &mut source_root, "/main.rs", text); 40 let file_id = db.add_file(WORKSPACE, "/", &mut source_root, "/main.rs", text);
40 db.set_source_root(WORKSPACE, Arc::new(source_root.clone())); 41 db.set_source_root(WORKSPACE, Arc::new(source_root.clone()));
41 (db, source_root, file_id) 42 (db, source_root, file_id)
42 } 43 }
43 44
44 pub fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { 45 pub fn with_position(fixture: &str) -> (MockDatabase, FilePosition) {
45 let (db, _, position) = MockDatabase::from_fixture(fixture); 46 let (db, position) = MockDatabase::from_fixture(fixture);
46 let position = position.expect("expected a marker ( <|> )"); 47 let position = position.expect("expected a marker ( <|> )");
47 (db, position) 48 (db, position)
48 } 49 }
49 50
50 fn from_fixture(fixture: &str) -> (MockDatabase, SourceRoot, Option<FilePosition>) { 51 pub fn file_id_of(&self, path: &str) -> FileId {
52 match self.files.get(path) {
53 Some(it) => *it,
54 None => panic!("unknown file: {:?}\nexisting files:\n{:#?}", path, self.files),
55 }
56 }
57
58 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
59 let mut ids = FxHashMap::default();
60 let mut crate_graph = CrateGraph::default();
61 for (crate_name, (crate_root, _)) in graph.0.iter() {
62 let crate_root = self.file_id_of(&crate_root);
63 let crate_id = crate_graph.add_crate_root(crate_root);
64 ids.insert(crate_name, crate_id);
65 }
66 for (crate_name, (_, deps)) in graph.0.iter() {
67 let from = ids[crate_name];
68 for dep in deps {
69 let to = ids[dep];
70 crate_graph.add_dep(from, dep.as_str().into(), to).unwrap();
71 }
72 }
73 self.set_crate_graph(Arc::new(crate_graph))
74 }
75
76 fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) {
51 let mut db = MockDatabase::default(); 77 let mut db = MockDatabase::default();
52 78
53 let (source_root, pos) = db.add_fixture(WORKSPACE, fixture); 79 let pos = db.add_fixture(fixture);
54 80
55 (db, source_root, pos) 81 (db, pos)
56 } 82 }
57 83
58 pub fn add_fixture( 84 fn add_fixture(&mut self, fixture: &str) -> Option<FilePosition> {
59 &mut self,
60 source_root_id: SourceRootId,
61 fixture: &str,
62 ) -> (SourceRoot, Option<FilePosition>) {
63 let mut position = None; 85 let mut position = None;
64 let mut source_root = SourceRoot::default(); 86 let mut source_root = SourceRoot::default();
87 let mut source_root_id = WORKSPACE;
88 let mut source_root_prefix = "/".to_string();
65 for entry in parse_fixture(fixture) { 89 for entry in parse_fixture(fixture) {
90 if entry.meta.starts_with("root") {
91 self.set_source_root(source_root_id, Arc::new(source_root));
92 source_root = SourceRoot::default();
93
94 source_root_id = SourceRootId(source_root_id.0 + 1);
95 source_root_prefix = entry.meta["root".len()..].trim().to_string();
96 continue;
97 }
66 if entry.text.contains(CURSOR_MARKER) { 98 if entry.text.contains(CURSOR_MARKER) {
67 assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); 99 assert!(position.is_none(), "only one marker (<|>) per fixture is allowed");
68 position = Some(self.add_file_with_position( 100 position = Some(self.add_file_with_position(
69 source_root_id, 101 source_root_id,
102 &source_root_prefix,
70 &mut source_root, 103 &mut source_root,
71 &entry.meta, 104 &entry.meta,
72 &entry.text, 105 &entry.text,
73 )); 106 ));
74 } else { 107 } else {
75 self.add_file(source_root_id, &mut source_root, &entry.meta, &entry.text); 108 self.add_file(
109 source_root_id,
110 &source_root_prefix,
111 &mut source_root,
112 &entry.meta,
113 &entry.text,
114 );
76 } 115 }
77 } 116 }
78 self.set_source_root(source_root_id, Arc::new(source_root.clone())); 117 self.set_source_root(source_root_id, Arc::new(source_root));
79 (source_root, position) 118 position
80 } 119 }
81 120
82 fn add_file( 121 fn add_file(
83 &mut self, 122 &mut self,
84 source_root_id: SourceRootId, 123 source_root_id: SourceRootId,
124 source_root_prefix: &str,
85 source_root: &mut SourceRoot, 125 source_root: &mut SourceRoot,
86 path: &str, 126 path: &str,
87 text: &str, 127 text: &str,
88 ) -> FileId { 128 ) -> FileId {
89 assert!(path.starts_with('/')); 129 assert!(source_root_prefix.starts_with('/'));
90 let is_crate_root = path == "/lib.rs" || path == "/main.rs"; 130 assert!(source_root_prefix.ends_with('/'));
131 assert!(path.starts_with(source_root_prefix));
132 let rel_path = RelativePathBuf::from_path(&path[source_root_prefix.len()..]).unwrap();
133
134 let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs";
91 135
92 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 136 let file_id = FileId(self.files.len() as u32);
93 let file_id = FileId(self.file_counter); 137 let prev = self.files.insert(path.to_string(), file_id);
94 self.file_counter += 1; 138 assert!(prev.is_none(), "duplicate files in the text fixture");
95 let text = Arc::new(text.to_string()); 139 let text = Arc::new(text.to_string());
96 self.set_file_text(file_id, text); 140 self.set_file_text(file_id, text);
97 self.set_file_relative_path(file_id, path.clone()); 141 self.set_file_relative_path(file_id, rel_path.clone());
98 self.set_file_source_root(file_id, source_root_id); 142 self.set_file_source_root(file_id, source_root_id);
99 source_root.files.insert(path, file_id); 143 source_root.files.insert(rel_path, file_id);
100 144
101 if is_crate_root { 145 if is_crate_root {
102 let mut crate_graph = CrateGraph::default(); 146 let mut crate_graph = CrateGraph::default();
@@ -109,12 +153,13 @@ impl MockDatabase {
109 fn add_file_with_position( 153 fn add_file_with_position(
110 &mut self, 154 &mut self,
111 source_root_id: SourceRootId, 155 source_root_id: SourceRootId,
156 source_root_prefix: &str,
112 source_root: &mut SourceRoot, 157 source_root: &mut SourceRoot,
113 path: &str, 158 path: &str,
114 text: &str, 159 text: &str,
115 ) -> FilePosition { 160 ) -> FilePosition {
116 let (offset, text) = extract_offset(text); 161 let (offset, text) = extract_offset(text);
117 let file_id = self.add_file(source_root_id, source_root, path, &text); 162 let file_id = self.add_file(source_root_id, source_root_prefix, source_root, path, &text);
118 FilePosition { file_id, offset } 163 FilePosition { file_id, offset }
119 } 164 }
120} 165}
@@ -138,7 +183,7 @@ impl Default for MockDatabase {
138 events: Default::default(), 183 events: Default::default(),
139 runtime: salsa::Runtime::default(), 184 runtime: salsa::Runtime::default(),
140 interner: Default::default(), 185 interner: Default::default(),
141 file_counter: 0, 186 files: FxHashMap::default(),
142 }; 187 };
143 db.set_crate_graph(Default::default()); 188 db.set_crate_graph(Default::default());
144 db 189 db
@@ -151,7 +196,8 @@ impl salsa::ParallelDatabase for MockDatabase {
151 events: Default::default(), 196 events: Default::default(),
152 runtime: self.runtime.snapshot(self), 197 runtime: self.runtime.snapshot(self),
153 interner: Arc::clone(&self.interner), 198 interner: Arc::clone(&self.interner),
154 file_counter: self.file_counter, 199 // only the root database can be used to get file_id by path.
200 files: FxHashMap::default(),
155 }) 201 })
156 } 202 }
157} 203}
@@ -184,3 +230,20 @@ impl MockDatabase {
184 .collect() 230 .collect()
185 } 231 }
186} 232}
233
234#[derive(Default)]
235pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>);
236
237#[macro_export]
238macro_rules! crate_graph {
239 ($($crate_name:literal: ($crate_path:literal, [$($dep:literal),*]),)*) => {{
240 let mut res = $crate::mock::CrateGraphFixture::default();
241 $(
242 res.0.insert(
243 $crate_name.to_string(),
244 ($crate_path.to_string(), vec![$($dep.to_string()),*])
245 );
246 )*
247 res
248 }}
249}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 9c0e4ef29..9b621fbc2 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -1,7 +1,6 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::{CrateGraph, SourceRootId, SourceDatabase}; 3use ra_db::SourceDatabase;
4use relative_path::RelativePath;
5use test_utils::{assert_eq_text, covers}; 4use test_utils::{assert_eq_text, covers};
6 5
7use crate::{ 6use crate::{
@@ -20,20 +19,6 @@ fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
20 (db.item_map(krate), module_id) 19 (db.item_map(krate), module_id)
21} 20}
22 21
23/// Sets the crate root to the file of the cursor marker
24fn item_map_custom_crate_root(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
25 let (mut db, pos) = MockDatabase::with_position(fixture);
26
27 let mut crate_graph = CrateGraph::default();
28 crate_graph.add_crate_root(pos.file_id);
29 db.set_crate_graph(Arc::new(crate_graph));
30
31 let module = crate::source_binder::module_from_position(&db, pos).unwrap();
32 let krate = module.krate(&db).unwrap();
33 let module_id = module.module_id;
34 (db.item_map(krate), module_id)
35}
36
37fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { 22fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
38 let mut lines = map[module_id] 23 let mut lines = map[module_id]
39 .items 24 .items
@@ -252,24 +237,20 @@ fn glob_enum() {
252#[test] 237#[test]
253fn glob_across_crates() { 238fn glob_across_crates() {
254 covers!(glob_across_crates); 239 covers!(glob_across_crates);
255 let (mut db, sr) = MockDatabase::with_files( 240 let mut db = MockDatabase::with_files(
256 " 241 "
257 //- /main.rs 242 //- /main.rs
258 use test_crate::*; 243 use test_crate::*;
259 244
260 //- /lib.rs 245 //- /lib.rs
261 pub struct Baz; 246 pub struct Baz;
262 ", 247 ",
263 ); 248 );
264 let main_id = sr.files[RelativePath::new("/main.rs")]; 249 db.set_crate_graph_from_fixture(crate_graph! {
265 let lib_id = sr.files[RelativePath::new("/lib.rs")]; 250 "main": ("/main.rs", ["test_crate"]),
266 251 "test_crate": ("/lib.rs", []),
267 let mut crate_graph = CrateGraph::default(); 252 });
268 let main_crate = crate_graph.add_crate_root(main_id); 253 let main_id = db.file_id_of("/main.rs");
269 let lib_crate = crate_graph.add_crate_root(lib_id);
270 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
271
272 db.set_crate_graph(Arc::new(crate_graph));
273 254
274 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 255 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
275 let krate = module.krate(&db).unwrap(); 256 let krate = module.krate(&db).unwrap();
@@ -286,22 +267,31 @@ fn glob_across_crates() {
286 267
287#[test] 268#[test]
288fn module_resolution_works_for_non_standard_filenames() { 269fn module_resolution_works_for_non_standard_filenames() {
289 let (item_map, module_id) = item_map_custom_crate_root( 270 let mut db = MockDatabase::with_files(
290 " 271 "
291 //- /my_library.rs 272 //- /my_library.rs
292 mod foo; 273 mod foo;
293 use self::foo::Bar; 274 use self::foo::Bar;
294 <|> 275
295 //- /foo/mod.rs 276 //- /foo/mod.rs
296 pub struct Bar; 277 pub struct Bar;
297 ", 278 ",
298 ); 279 );
280 db.set_crate_graph_from_fixture(crate_graph! {
281 "my_library": ("/my_library.rs", []),
282 });
283 let file_id = db.file_id_of("/my_library.rs");
284
285 let module = crate::source_binder::module_from_file_id(&db, file_id).unwrap();
286 let krate = module.krate(&db).unwrap();
287 let module_id = module.module_id;
288 let item_map = db.item_map(krate);
299 check_module_item_map( 289 check_module_item_map(
300 &item_map, 290 &item_map,
301 module_id, 291 module_id,
302 " 292 "
303 Bar: t v 293 Bar: t v
304 foo: t 294 foo: t
305 ", 295 ",
306 ); 296 );
307} 297}
@@ -411,24 +401,20 @@ fn item_map_enum_importing() {
411 401
412#[test] 402#[test]
413fn item_map_across_crates() { 403fn item_map_across_crates() {
414 let (mut db, sr) = MockDatabase::with_files( 404 let mut db = MockDatabase::with_files(
415 " 405 "
416 //- /main.rs 406 //- /main.rs
417 use test_crate::Baz; 407 use test_crate::Baz;
418 408
419 //- /lib.rs 409 //- /lib.rs
420 pub struct Baz; 410 pub struct Baz;
421 ", 411 ",
422 ); 412 );
423 let main_id = sr.files[RelativePath::new("/main.rs")]; 413 db.set_crate_graph_from_fixture(crate_graph! {
424 let lib_id = sr.files[RelativePath::new("/lib.rs")]; 414 "main": ("/main.rs", ["test_crate"]),
425 415 "test_crate": ("/lib.rs", []),
426 let mut crate_graph = CrateGraph::default(); 416 });
427 let main_crate = crate_graph.add_crate_root(main_id); 417 let main_id = db.file_id_of("/main.rs");
428 let lib_crate = crate_graph.add_crate_root(lib_id);
429 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
430
431 db.set_crate_graph(Arc::new(crate_graph));
432 418
433 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 419 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
434 let krate = module.krate(&db).unwrap(); 420 let krate = module.krate(&db).unwrap();
@@ -438,14 +424,14 @@ fn item_map_across_crates() {
438 &item_map, 424 &item_map,
439 module.module_id, 425 module.module_id,
440 " 426 "
441 Baz: t v 427 Baz: t v
442 ", 428 ",
443 ); 429 );
444} 430}
445 431
446#[test] 432#[test]
447fn extern_crate_rename() { 433fn extern_crate_rename() {
448 let (mut db, sr) = MockDatabase::with_files( 434 let mut db = MockDatabase::with_files(
449 " 435 "
450 //- /main.rs 436 //- /main.rs
451 extern crate alloc as alloc_crate; 437 extern crate alloc as alloc_crate;
@@ -458,18 +444,13 @@ fn extern_crate_rename() {
458 444
459 //- /lib.rs 445 //- /lib.rs
460 struct Arc; 446 struct Arc;
461 ", 447 ",
462 ); 448 );
463 let main_id = sr.files[RelativePath::new("/main.rs")]; 449 db.set_crate_graph_from_fixture(crate_graph! {
464 let sync_id = sr.files[RelativePath::new("/sync.rs")]; 450 "main": ("/main.rs", ["alloc"]),
465 let lib_id = sr.files[RelativePath::new("/lib.rs")]; 451 "alloc": ("/lib.rs", []),
466 452 });
467 let mut crate_graph = CrateGraph::default(); 453 let sync_id = db.file_id_of("/sync.rs");
468 let main_crate = crate_graph.add_crate_root(main_id);
469 let lib_crate = crate_graph.add_crate_root(lib_id);
470 crate_graph.add_dep(main_crate, "alloc".into(), lib_crate).unwrap();
471
472 db.set_crate_graph(Arc::new(crate_graph));
473 454
474 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap(); 455 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
475 let krate = module.krate(&db).unwrap(); 456 let krate = module.krate(&db).unwrap();
@@ -479,14 +460,14 @@ fn extern_crate_rename() {
479 &item_map, 460 &item_map,
480 module.module_id, 461 module.module_id,
481 " 462 "
482 Arc: t v 463 Arc: t v
483 ", 464 ",
484 ); 465 );
485} 466}
486 467
487#[test] 468#[test]
488fn import_across_source_roots() { 469fn import_across_source_roots() {
489 let (mut db, sr) = MockDatabase::with_files( 470 let mut db = MockDatabase::with_files(
490 " 471 "
491 //- /lib.rs 472 //- /lib.rs
492 pub mod a { 473 pub mod a {
@@ -494,29 +475,18 @@ fn import_across_source_roots() {
494 pub struct C; 475 pub struct C;
495 } 476 }
496 } 477 }
497 ",
498 );
499 let lib_id = sr.files[RelativePath::new("/lib.rs")];
500 478
501 let source_root = SourceRootId(1); 479 //- root /main/
502 480
503 let (sr2, pos) = db.add_fixture( 481 //- /main/main.rs
504 source_root,
505 "
506 //- /main.rs
507 use test_crate::a::b::C; 482 use test_crate::a::b::C;
508 ", 483 ",
509 ); 484 );
510 assert!(pos.is_none()); 485 db.set_crate_graph_from_fixture(crate_graph! {
511 486 "main": ("/main/main.rs", ["test_crate"]),
512 let main_id = sr2.files[RelativePath::new("/main.rs")]; 487 "test_crate": ("/lib.rs", []),
513 488 });
514 let mut crate_graph = CrateGraph::default(); 489 let main_id = db.file_id_of("/main/main.rs");
515 let main_crate = crate_graph.add_crate_root(main_id);
516 let lib_crate = crate_graph.add_crate_root(lib_id);
517 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
518
519 db.set_crate_graph(Arc::new(crate_graph));
520 490
521 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 491 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
522 let krate = module.krate(&db).unwrap(); 492 let krate = module.krate(&db).unwrap();
@@ -533,7 +503,7 @@ fn import_across_source_roots() {
533 503
534#[test] 504#[test]
535fn reexport_across_crates() { 505fn reexport_across_crates() {
536 let (mut db, sr) = MockDatabase::with_files( 506 let mut db = MockDatabase::with_files(
537 " 507 "
538 //- /main.rs 508 //- /main.rs
539 use test_crate::Baz; 509 use test_crate::Baz;
@@ -545,17 +515,13 @@ fn reexport_across_crates() {
545 515
546 //- /foo.rs 516 //- /foo.rs
547 pub struct Baz; 517 pub struct Baz;
548 ", 518 ",
549 ); 519 );
550 let main_id = sr.files[RelativePath::new("/main.rs")]; 520 db.set_crate_graph_from_fixture(crate_graph! {
551 let lib_id = sr.files[RelativePath::new("/lib.rs")]; 521 "main": ("/main.rs", ["test_crate"]),
552 522 "test_crate": ("/lib.rs", []),
553 let mut crate_graph = CrateGraph::default(); 523 });
554 let main_crate = crate_graph.add_crate_root(main_id); 524 let main_id = db.file_id_of("/main.rs");
555 let lib_crate = crate_graph.add_crate_root(lib_id);
556 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
557
558 db.set_crate_graph(Arc::new(crate_graph));
559 525
560 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 526 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
561 let krate = module.krate(&db).unwrap(); 527 let krate = module.krate(&db).unwrap();
@@ -565,7 +531,7 @@ fn reexport_across_crates() {
565 &item_map, 531 &item_map,
566 module.module_id, 532 module.module_id,
567 " 533 "
568 Baz: t v 534 Baz: t v
569 ", 535 ",
570 ); 536 );
571} 537}