diff options
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 95 |
2 files changed, 119 insertions, 5 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 951468a98..9f197bb58 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use arrayvec::ArrayVec; | 1 | use arrayvec::ArrayVec; |
2 | use ra_db::FileId; | 2 | use ra_db::FileId; |
3 | use ra_syntax::ast; | 3 | use ra_syntax::{ast, SmolStr}; |
4 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -509,10 +509,16 @@ where | |||
509 | .collect(&*items); | 509 | .collect(&*items); |
510 | } | 510 | } |
511 | // out of line module, resolve, parse and recurse | 511 | // out of line module, resolve, parse and recurse |
512 | raw::ModuleData::Declaration { name, ast_id, .. } => { | 512 | raw::ModuleData::Declaration { name, ast_id, attr_path } => { |
513 | let ast_id = ast_id.with_file_id(self.file_id); | 513 | let ast_id = ast_id.with_file_id(self.file_id); |
514 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); | 514 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); |
515 | match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) { | 515 | match resolve_submodule( |
516 | self.def_collector.db, | ||
517 | self.file_id, | ||
518 | name, | ||
519 | is_root, | ||
520 | attr_path.as_ref(), | ||
521 | ) { | ||
516 | Ok(file_id) => { | 522 | Ok(file_id) => { |
517 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 523 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
518 | let raw_items = self.def_collector.db.raw_items(file_id.into()); | 524 | let raw_items = self.def_collector.db.raw_items(file_id.into()); |
@@ -626,6 +632,7 @@ fn resolve_submodule( | |||
626 | file_id: HirFileId, | 632 | file_id: HirFileId, |
627 | name: &Name, | 633 | name: &Name, |
628 | is_root: bool, | 634 | is_root: bool, |
635 | attr_path: Option<&SmolStr>, | ||
629 | ) -> Result<FileId, RelativePathBuf> { | 636 | ) -> Result<FileId, RelativePathBuf> { |
630 | // FIXME: handle submodules of inline modules properly | 637 | // FIXME: handle submodules of inline modules properly |
631 | let file_id = file_id.original_file(db); | 638 | let file_id = file_id.original_file(db); |
@@ -639,7 +646,13 @@ fn resolve_submodule( | |||
639 | let file_mod = dir_path.join(format!("{}.rs", name)); | 646 | let file_mod = dir_path.join(format!("{}.rs", name)); |
640 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | 647 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); |
641 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); | 648 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); |
642 | let mut candidates = ArrayVec::<[_; 2]>::new(); | 649 | let mut candidates = ArrayVec::<[_; 3]>::new(); |
650 | let file_attr_mod = attr_path.map(|file_path| { | ||
651 | let file_attr_mod = dir_path.join(file_path.to_string()); | ||
652 | candidates.push(file_attr_mod.clone()); | ||
653 | |||
654 | file_attr_mod | ||
655 | }); | ||
643 | if is_dir_owner { | 656 | if is_dir_owner { |
644 | candidates.push(file_mod.clone()); | 657 | candidates.push(file_mod.clone()); |
645 | candidates.push(dir_mod); | 658 | candidates.push(dir_mod); |
@@ -651,7 +664,13 @@ fn resolve_submodule( | |||
651 | // FIXME: handle ambiguity | 664 | // FIXME: handle ambiguity |
652 | match points_to.next() { | 665 | match points_to.next() { |
653 | Some(file_id) => Ok(file_id), | 666 | Some(file_id) => Ok(file_id), |
654 | None => Err(if is_dir_owner { file_mod } else { file_dir_mod }), | 667 | None => { |
668 | if let Some(file_attr_mod) = file_attr_mod { | ||
669 | Err(file_attr_mod) | ||
670 | } else { | ||
671 | Err(if is_dir_owner { file_mod } else { file_dir_mod }) | ||
672 | } | ||
673 | } | ||
655 | } | 674 | } |
656 | } | 675 | } |
657 | 676 | ||
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index bd2d855cf..5e8ea6780 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -365,6 +365,101 @@ fn module_resolution_works_for_raw_modules() { | |||
365 | } | 365 | } |
366 | 366 | ||
367 | #[test] | 367 | #[test] |
368 | fn module_resolution_decl_path() { | ||
369 | let map = def_map_with_crate_graph( | ||
370 | " | ||
371 | //- /library.rs | ||
372 | #[path = \"bar/baz/foo.rs\"] | ||
373 | mod foo; | ||
374 | use self::foo::Bar; | ||
375 | |||
376 | //- /bar/baz/foo.rs | ||
377 | pub struct Bar; | ||
378 | ", | ||
379 | crate_graph! { | ||
380 | "library": ("/library.rs", []), | ||
381 | }, | ||
382 | ); | ||
383 | |||
384 | assert_snapshot_matches!(map, @r###" | ||
385 | ⋮crate | ||
386 | ⋮Bar: t v | ||
387 | ⋮foo: t | ||
388 | ⋮ | ||
389 | ⋮crate::foo | ||
390 | ⋮Bar: t v | ||
391 | "###); | ||
392 | } | ||
393 | |||
394 | #[test] | ||
395 | fn module_resolution_module_with_path_in_mod_rs() { | ||
396 | let map = def_map_with_crate_graph( | ||
397 | " | ||
398 | //- /main.rs | ||
399 | mod foo; | ||
400 | |||
401 | //- /foo/mod.rs | ||
402 | #[path = \"baz.rs\"] | ||
403 | pub mod bar; | ||
404 | |||
405 | use self::bar::Baz; | ||
406 | |||
407 | //- /foo/baz.rs | ||
408 | pub struct Baz; | ||
409 | ", | ||
410 | crate_graph! { | ||
411 | "main": ("/main.rs", []), | ||
412 | }, | ||
413 | ); | ||
414 | |||
415 | assert_snapshot_matches!(map, @r###" | ||
416 | ⋮crate | ||
417 | ⋮foo: t | ||
418 | ⋮ | ||
419 | ⋮crate::foo | ||
420 | ⋮Baz: t v | ||
421 | ⋮bar: t | ||
422 | ⋮ | ||
423 | ⋮crate::foo::bar | ||
424 | ⋮Baz: t v | ||
425 | "###); | ||
426 | } | ||
427 | |||
428 | #[test] | ||
429 | fn module_resolution_module_with_path_non_crate_root() { | ||
430 | let map = def_map_with_crate_graph( | ||
431 | " | ||
432 | //- /main.rs | ||
433 | mod foo; | ||
434 | |||
435 | //- /foo.rs | ||
436 | #[path = \"baz.rs\"] | ||
437 | pub mod bar; | ||
438 | |||
439 | use self::bar::Baz; | ||
440 | |||
441 | //- /baz.rs | ||
442 | pub struct Baz; | ||
443 | ", | ||
444 | crate_graph! { | ||
445 | "main": ("/main.rs", []), | ||
446 | }, | ||
447 | ); | ||
448 | |||
449 | assert_snapshot_matches!(map, @r###" | ||
450 | ⋮crate | ||
451 | ⋮foo: t | ||
452 | ⋮ | ||
453 | ⋮crate::foo | ||
454 | ⋮Baz: t v | ||
455 | ⋮bar: t | ||
456 | ⋮ | ||
457 | ⋮crate::foo::bar | ||
458 | ⋮Baz: t v | ||
459 | "###); | ||
460 | } | ||
461 | |||
462 | #[test] | ||
368 | fn name_res_works_for_broken_modules() { | 463 | fn name_res_works_for_broken_modules() { |
369 | covers!(name_res_works_for_broken_modules); | 464 | covers!(name_res_works_for_broken_modules); |
370 | let map = def_map( | 465 | let map = def_map( |