diff options
author | Alexander Andreev <[email protected]> | 2019-07-29 07:54:40 +0100 |
---|---|---|
committer | Alexander Andreev <[email protected]> | 2019-07-29 07:54:40 +0100 |
commit | 538ec1122baeccd85ab672fd0a9f1186d2171058 (patch) | |
tree | bd678af17b28232a43ac8c563d019d8a736641b5 /crates/ra_hir | |
parent | de278d164906d6d29974790c5a4db28303692484 (diff) |
Added resolve modules inside inline module
#1510
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 148 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/mods.rs | 53 |
2 files changed, 147 insertions, 54 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7f765caf3..80b71e2d9 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::borrow::Cow; | 1 | use std::borrow::Cow; |
2 | use std::sync::Arc; | ||
2 | 3 | ||
3 | use arrayvec::ArrayVec; | 4 | use ra_db::{FileId, SourceRoot}; |
4 | use ra_db::FileId; | ||
5 | use ra_syntax::{ast, SmolStr}; | 5 | use ra_syntax::{ast, SmolStr}; |
6 | use relative_path::RelativePathBuf; | 6 | use relative_path::RelativePathBuf; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
@@ -106,7 +106,7 @@ where | |||
106 | file_id: file_id.into(), | 106 | file_id: file_id.into(), |
107 | raw_items: &raw_items, | 107 | raw_items: &raw_items, |
108 | } | 108 | } |
109 | .collect(raw_items.items()); | 109 | .collect(None, raw_items.items()); |
110 | 110 | ||
111 | // main name resolution fixed-point loop. | 111 | // main name resolution fixed-point loop. |
112 | let mut i = 0; | 112 | let mut i = 0; |
@@ -456,7 +456,7 @@ where | |||
456 | let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); | 456 | let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); |
457 | let raw_items = self.db.raw_items(file_id); | 457 | let raw_items = self.db.raw_items(file_id); |
458 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } | 458 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } |
459 | .collect(raw_items.items()); | 459 | .collect(None, raw_items.items()); |
460 | } else { | 460 | } else { |
461 | log::error!("Too deep macro expansion: {:?}", macro_call_id); | 461 | log::error!("Too deep macro expansion: {:?}", macro_call_id); |
462 | self.def_map.poison_macros.insert(macro_def_id); | 462 | self.def_map.poison_macros.insert(macro_def_id); |
@@ -482,10 +482,10 @@ impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | |||
482 | where | 482 | where |
483 | DB: DefDatabase, | 483 | DB: DefDatabase, |
484 | { | 484 | { |
485 | fn collect(&mut self, items: &[raw::RawItem]) { | 485 | fn collect(&mut self, parent_module: Option<&Name>, items: &[raw::RawItem]) { |
486 | for item in items { | 486 | for item in items { |
487 | match *item { | 487 | match *item { |
488 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 488 | raw::RawItem::Module(m) => self.collect_module(parent_module, &self.raw_items[m]), |
489 | raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( | 489 | raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( |
490 | self.module_id, | 490 | self.module_id, |
491 | import, | 491 | import, |
@@ -497,7 +497,7 @@ where | |||
497 | } | 497 | } |
498 | } | 498 | } |
499 | 499 | ||
500 | fn collect_module(&mut self, module: &raw::ModuleData) { | 500 | fn collect_module(&mut self, _module: Option<&Name>, module: &raw::ModuleData) { |
501 | match module { | 501 | match module { |
502 | // inline module, just recurse | 502 | // inline module, just recurse |
503 | raw::ModuleData::Definition { name, items, ast_id } => { | 503 | raw::ModuleData::Definition { name, items, ast_id } => { |
@@ -509,7 +509,7 @@ where | |||
509 | file_id: self.file_id, | 509 | file_id: self.file_id, |
510 | raw_items: self.raw_items, | 510 | raw_items: self.raw_items, |
511 | } | 511 | } |
512 | .collect(&*items); | 512 | .collect(Some(name), &*items); |
513 | } | 513 | } |
514 | // out of line module, resolve, parse and recurse | 514 | // out of line module, resolve, parse and recurse |
515 | raw::ModuleData::Declaration { name, ast_id, attr_path } => { | 515 | raw::ModuleData::Declaration { name, ast_id, attr_path } => { |
@@ -521,6 +521,7 @@ where | |||
521 | name, | 521 | name, |
522 | is_root, | 522 | is_root, |
523 | attr_path.as_ref(), | 523 | attr_path.as_ref(), |
524 | _module, | ||
524 | ) { | 525 | ) { |
525 | Ok(file_id) => { | 526 | Ok(file_id) => { |
526 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 527 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
@@ -531,7 +532,7 @@ where | |||
531 | file_id: file_id.into(), | 532 | file_id: file_id.into(), |
532 | raw_items: &raw_items, | 533 | raw_items: &raw_items, |
533 | } | 534 | } |
534 | .collect(raw_items.items()) | 535 | .collect(None, raw_items.items()) |
535 | } | 536 | } |
536 | Err(candidate) => self.def_collector.def_map.diagnostics.push( | 537 | Err(candidate) => self.def_collector.def_map.diagnostics.push( |
537 | DefDiagnostic::UnresolvedModule { | 538 | DefDiagnostic::UnresolvedModule { |
@@ -636,46 +637,47 @@ fn resolve_submodule( | |||
636 | name: &Name, | 637 | name: &Name, |
637 | is_root: bool, | 638 | is_root: bool, |
638 | attr_path: Option<&SmolStr>, | 639 | attr_path: Option<&SmolStr>, |
640 | parent_module: Option<&Name>, | ||
639 | ) -> Result<FileId, RelativePathBuf> { | 641 | ) -> Result<FileId, RelativePathBuf> { |
640 | // FIXME: handle submodules of inline modules properly | ||
641 | let file_id = file_id.original_file(db); | 642 | let file_id = file_id.original_file(db); |
642 | let source_root_id = db.file_source_root(file_id); | 643 | let source_root_id = db.file_source_root(file_id); |
643 | let path = db.file_relative_path(file_id); | 644 | let path = db.file_relative_path(file_id); |
644 | let root = RelativePathBuf::default(); | 645 | let root = RelativePathBuf::default(); |
645 | let dir_path = path.parent().unwrap_or(&root); | 646 | let dir_path = path.parent().unwrap_or(&root); |
646 | let mod_name = path.file_stem().unwrap_or("unknown"); | 647 | let mod_name = path.file_stem().unwrap_or("unknown"); |
647 | let is_dir_owner = is_root || mod_name == "mod"; | 648 | |
648 | 649 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | |
649 | let file_mod = dir_path.join(format!("{}.rs", name)); | 650 | (Some(file_path), Some(parent_name)) => { |
650 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | 651 | let file_path = normalize_attribute_path(file_path); |
651 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); | 652 | let path = dir_path.join(format!("{}/{}", parent_name, file_path)).normalize(); |
652 | let mut candidates = ArrayVec::<[_; 3]>::new(); | 653 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(path)) |
653 | let file_attr_mod = attr_path.map(|file_path| { | 654 | } |
654 | let file_path = normalize_attribute_path(file_path); | 655 | (Some(file_path), None) => { |
655 | let file_attr_mod = dir_path.join(file_path.as_ref()).normalize(); | 656 | let file_path = normalize_attribute_path(file_path); |
656 | candidates.push(file_attr_mod.clone()); | 657 | let path = dir_path.join(file_path.as_ref()).normalize(); |
657 | 658 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | |
658 | file_attr_mod | 659 | } |
659 | }); | 660 | (None, Some(parent_name)) => { |
660 | if is_dir_owner { | 661 | let path = dir_path.join(format!("{}/{}.rs", parent_name, name)); |
661 | candidates.push(file_mod.clone()); | 662 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) |
662 | candidates.push(dir_mod); | 663 | } |
663 | } else { | 664 | _ => { |
664 | candidates.push(file_dir_mod.clone()); | 665 | let is_dir_owner = is_root || mod_name == "mod"; |
665 | }; | 666 | if is_dir_owner { |
666 | let sr = db.source_root(source_root_id); | 667 | let file_mod = dir_path.join(format!("{}.rs", name)); |
667 | let mut points_to = candidates.into_iter().filter_map(|path| sr.files.get(&path)).copied(); | 668 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); |
668 | // FIXME: handle ambiguity | 669 | ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { |
669 | match points_to.next() { | 670 | file: file_mod, |
670 | Some(file_id) => Ok(file_id), | 671 | directory: dir_mod, |
671 | None => { | 672 | }) |
672 | if let Some(file_attr_mod) = file_attr_mod { | ||
673 | Err(file_attr_mod) | ||
674 | } else { | 673 | } else { |
675 | Err(if is_dir_owner { file_mod } else { file_dir_mod }) | 674 | let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); |
675 | ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) | ||
676 | } | 676 | } |
677 | } | 677 | } |
678 | } | 678 | }; |
679 | |||
680 | resolve_mode.resolve(db.source_root(source_root_id)) | ||
679 | } | 681 | } |
680 | 682 | ||
681 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | 683 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { |
@@ -693,6 +695,74 @@ fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | |||
693 | } | 695 | } |
694 | } | 696 | } |
695 | 697 | ||
698 | enum OutOfLineMode { | ||
699 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
700 | FileInDirectory(RelativePathBuf), | ||
701 | WithAttributePath(RelativePathBuf), | ||
702 | } | ||
703 | |||
704 | impl OutOfLineMode { | ||
705 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
706 | match self { | ||
707 | OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) { | ||
708 | None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), | ||
709 | file_id => resolve_find_result(file_id, file), | ||
710 | }, | ||
711 | OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), | ||
712 | OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), | ||
713 | } | ||
714 | } | ||
715 | } | ||
716 | |||
717 | enum InsideInlineModuleMode { | ||
718 | File(RelativePathBuf), | ||
719 | WithAttributePath(RelativePathBuf), | ||
720 | } | ||
721 | |||
722 | impl InsideInlineModuleMode { | ||
723 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
724 | match self { | ||
725 | InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), | ||
726 | InsideInlineModuleMode::WithAttributePath(path) => { | ||
727 | resolve_simple_path(source_root, path) | ||
728 | } | ||
729 | } | ||
730 | } | ||
731 | } | ||
732 | |||
733 | enum ResolutionMode { | ||
734 | OutOfLine(OutOfLineMode), | ||
735 | InsideInlineModule(InsideInlineModuleMode), | ||
736 | } | ||
737 | |||
738 | impl ResolutionMode { | ||
739 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
740 | use self::ResolutionMode::*; | ||
741 | |||
742 | match self { | ||
743 | OutOfLine(mode) => mode.resolve(source_root), | ||
744 | InsideInlineModule(mode) => mode.resolve(source_root), | ||
745 | } | ||
746 | } | ||
747 | } | ||
748 | |||
749 | fn resolve_simple_path( | ||
750 | source_root: Arc<SourceRoot>, | ||
751 | path: &RelativePathBuf, | ||
752 | ) -> Result<FileId, RelativePathBuf> { | ||
753 | resolve_find_result(source_root.files.get(path), path) | ||
754 | } | ||
755 | |||
756 | fn resolve_find_result( | ||
757 | file_id: Option<&FileId>, | ||
758 | path: &RelativePathBuf, | ||
759 | ) -> Result<FileId, RelativePathBuf> { | ||
760 | match file_id { | ||
761 | Some(file_id) => Ok(file_id.clone()), | ||
762 | None => Err(path.clone()), | ||
763 | } | ||
764 | } | ||
765 | |||
696 | #[cfg(test)] | 766 | #[cfg(test)] |
697 | mod tests { | 767 | mod tests { |
698 | use ra_db::SourceDatabase; | 768 | use ra_db::SourceDatabase; |
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs index d714a3276..382728149 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mods.rs | |||
@@ -336,10 +336,10 @@ fn module_resolution_explicit_path_mod_rs_with_win_separator() { | |||
336 | "###); | 336 | "###); |
337 | } | 337 | } |
338 | 338 | ||
339 | // FIXME: issue #1510. not support out-of-line modules inside inline. | 339 | // FIXME: issue #1529. not support out-of-line modules inside inline. |
340 | #[test] | 340 | #[test] |
341 | #[ignore] | 341 | #[ignore] |
342 | fn module_resolution_decl_inside_inline_module() { | 342 | fn module_resolution_decl_inside_inline_module_with_path_attribute() { |
343 | let map = def_map_with_crate_graph( | 343 | let map = def_map_with_crate_graph( |
344 | r###" | 344 | r###" |
345 | //- /main.rs | 345 | //- /main.rs |
@@ -368,10 +368,39 @@ fn module_resolution_decl_inside_inline_module() { | |||
368 | "###); | 368 | "###); |
369 | } | 369 | } |
370 | 370 | ||
371 | // FIXME: issue #1510. not support out-of-line modules inside inline. | 371 | #[test] |
372 | fn module_resolution_decl_inside_inline_module() { | ||
373 | let map = def_map_with_crate_graph( | ||
374 | r###" | ||
375 | //- /main.rs | ||
376 | mod foo { | ||
377 | mod bar; | ||
378 | } | ||
379 | |||
380 | //- /foo/bar.rs | ||
381 | pub struct Baz; | ||
382 | "###, | ||
383 | crate_graph! { | ||
384 | "main": ("/main.rs", []), | ||
385 | }, | ||
386 | ); | ||
387 | |||
388 | assert_snapshot_matches!(map, @r###" | ||
389 | ⋮crate | ||
390 | ⋮foo: t | ||
391 | ⋮ | ||
392 | ⋮crate::foo | ||
393 | ⋮bar: t | ||
394 | ⋮ | ||
395 | ⋮crate::foo::bar | ||
396 | ⋮Baz: t v | ||
397 | "###); | ||
398 | } | ||
399 | |||
400 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
372 | #[test] | 401 | #[test] |
373 | #[ignore] | 402 | #[ignore] |
374 | fn module_resolution_decl_inside_inline_module_2() { | 403 | fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { |
375 | let map = def_map_with_crate_graph( | 404 | let map = def_map_with_crate_graph( |
376 | r###" | 405 | r###" |
377 | //- /main.rs | 406 | //- /main.rs |
@@ -400,7 +429,7 @@ fn module_resolution_decl_inside_inline_module_2() { | |||
400 | "###); | 429 | "###); |
401 | } | 430 | } |
402 | 431 | ||
403 | // FIXME: issue #1510. not support out-of-line modules inside inline. | 432 | // FIXME: issue #1529. not support out-of-line modules inside inline. |
404 | #[test] | 433 | #[test] |
405 | #[ignore] | 434 | #[ignore] |
406 | fn module_resolution_decl_inside_inline_module_3() { | 435 | fn module_resolution_decl_inside_inline_module_3() { |
@@ -433,7 +462,7 @@ fn module_resolution_decl_inside_inline_module_3() { | |||
433 | "###); | 462 | "###); |
434 | } | 463 | } |
435 | 464 | ||
436 | // FIXME: issue #1510. not support out-of-line modules inside inline. | 465 | // FIXME: issue #1529. not support out-of-line modules inside inline. |
437 | #[test] | 466 | #[test] |
438 | #[ignore] | 467 | #[ignore] |
439 | fn module_resolution_decl_inside_inline_module_empty_path() { | 468 | fn module_resolution_decl_inside_inline_module_empty_path() { |
@@ -491,7 +520,7 @@ fn module_resolution_decl_empty_path() { | |||
491 | "###); | 520 | "###); |
492 | } | 521 | } |
493 | 522 | ||
494 | // FIXME: issue #1510. not support out-of-line modules inside inline. | 523 | // FIXME: issue #1529. not support out-of-line modules inside inline. |
495 | #[test] | 524 | #[test] |
496 | #[ignore] | 525 | #[ignore] |
497 | fn module_resolution_decl_inside_inline_module_relative_path() { | 526 | fn module_resolution_decl_inside_inline_module_relative_path() { |
@@ -523,9 +552,7 @@ fn module_resolution_decl_inside_inline_module_relative_path() { | |||
523 | "###); | 552 | "###); |
524 | } | 553 | } |
525 | 554 | ||
526 | // FIXME: issue #1510. not support out-of-line modules inside inline. | ||
527 | #[test] | 555 | #[test] |
528 | #[ignore] | ||
529 | fn module_resolution_decl_inside_inline_module_in_crate_root() { | 556 | fn module_resolution_decl_inside_inline_module_in_crate_root() { |
530 | let map = def_map_with_crate_graph( | 557 | let map = def_map_with_crate_graph( |
531 | r###" | 558 | r###" |
@@ -557,9 +584,7 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() { | |||
557 | "###); | 584 | "###); |
558 | } | 585 | } |
559 | 586 | ||
560 | // FIXME: issue #1510. not support out-of-line modules inside inline. | ||
561 | #[test] | 587 | #[test] |
562 | #[ignore] | ||
563 | fn module_resolution_decl_inside_inline_module_in_mod_rs() { | 588 | fn module_resolution_decl_inside_inline_module_in_mod_rs() { |
564 | let map = def_map_with_crate_graph( | 589 | let map = def_map_with_crate_graph( |
565 | r###" | 590 | r###" |
@@ -597,9 +622,7 @@ fn module_resolution_decl_inside_inline_module_in_mod_rs() { | |||
597 | "###); | 622 | "###); |
598 | } | 623 | } |
599 | 624 | ||
600 | // FIXME: issue #1510. not support out-of-line modules inside inline. | ||
601 | #[test] | 625 | #[test] |
602 | #[ignore] | ||
603 | fn module_resolution_decl_inside_inline_module_in_non_crate_root() { | 626 | fn module_resolution_decl_inside_inline_module_in_non_crate_root() { |
604 | let map = def_map_with_crate_graph( | 627 | let map = def_map_with_crate_graph( |
605 | r###" | 628 | r###" |
@@ -613,7 +636,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() { | |||
613 | } | 636 | } |
614 | use self::bar::baz::Baz; | 637 | use self::bar::baz::Baz; |
615 | 638 | ||
616 | //- /foo/bar/qwe.rs | 639 | //- /bar/qwe.rs |
617 | pub struct Baz; | 640 | pub struct Baz; |
618 | "###, | 641 | "###, |
619 | crate_graph! { | 642 | crate_graph! { |
@@ -637,7 +660,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() { | |||
637 | "###); | 660 | "###); |
638 | } | 661 | } |
639 | 662 | ||
640 | // FIXME: issue #1510. not support out-of-line modules inside inline. | 663 | // FIXME: issue #1529. not support out-of-line modules inside inline. |
641 | #[test] | 664 | #[test] |
642 | #[ignore] | 665 | #[ignore] |
643 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { | 666 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { |