diff options
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 148 |
1 files changed, 114 insertions, 34 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7f765caf3..06b732215 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; |
@@ -105,6 +105,7 @@ where | |||
105 | module_id, | 105 | module_id, |
106 | file_id: file_id.into(), | 106 | file_id: file_id.into(), |
107 | raw_items: &raw_items, | 107 | raw_items: &raw_items, |
108 | parent_module: None, | ||
108 | } | 109 | } |
109 | .collect(raw_items.items()); | 110 | .collect(raw_items.items()); |
110 | 111 | ||
@@ -455,8 +456,14 @@ where | |||
455 | if !self.macro_stack_monitor.is_poison(macro_def_id) { | 456 | if !self.macro_stack_monitor.is_poison(macro_def_id) { |
456 | let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); | 457 | let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); |
457 | let raw_items = self.db.raw_items(file_id); | 458 | let raw_items = self.db.raw_items(file_id); |
458 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } | 459 | ModCollector { |
459 | .collect(raw_items.items()); | 460 | def_collector: &mut *self, |
461 | file_id, | ||
462 | module_id, | ||
463 | raw_items: &raw_items, | ||
464 | parent_module: None, | ||
465 | } | ||
466 | .collect(raw_items.items()); | ||
460 | } else { | 467 | } else { |
461 | log::error!("Too deep macro expansion: {:?}", macro_call_id); | 468 | log::error!("Too deep macro expansion: {:?}", macro_call_id); |
462 | self.def_map.poison_macros.insert(macro_def_id); | 469 | self.def_map.poison_macros.insert(macro_def_id); |
@@ -476,6 +483,7 @@ struct ModCollector<'a, D> { | |||
476 | module_id: CrateModuleId, | 483 | module_id: CrateModuleId, |
477 | file_id: HirFileId, | 484 | file_id: HirFileId, |
478 | raw_items: &'a raw::RawItems, | 485 | raw_items: &'a raw::RawItems, |
486 | parent_module: Option<&'a Name>, | ||
479 | } | 487 | } |
480 | 488 | ||
481 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | 489 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> |
@@ -508,6 +516,7 @@ where | |||
508 | module_id, | 516 | module_id, |
509 | file_id: self.file_id, | 517 | file_id: self.file_id, |
510 | raw_items: self.raw_items, | 518 | raw_items: self.raw_items, |
519 | parent_module: Some(name), | ||
511 | } | 520 | } |
512 | .collect(&*items); | 521 | .collect(&*items); |
513 | } | 522 | } |
@@ -521,6 +530,7 @@ where | |||
521 | name, | 530 | name, |
522 | is_root, | 531 | is_root, |
523 | attr_path.as_ref(), | 532 | attr_path.as_ref(), |
533 | self.parent_module, | ||
524 | ) { | 534 | ) { |
525 | Ok(file_id) => { | 535 | Ok(file_id) => { |
526 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 536 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
@@ -530,6 +540,7 @@ where | |||
530 | module_id, | 540 | module_id, |
531 | file_id: file_id.into(), | 541 | file_id: file_id.into(), |
532 | raw_items: &raw_items, | 542 | raw_items: &raw_items, |
543 | parent_module: None, | ||
533 | } | 544 | } |
534 | .collect(raw_items.items()) | 545 | .collect(raw_items.items()) |
535 | } | 546 | } |
@@ -636,46 +647,47 @@ fn resolve_submodule( | |||
636 | name: &Name, | 647 | name: &Name, |
637 | is_root: bool, | 648 | is_root: bool, |
638 | attr_path: Option<&SmolStr>, | 649 | attr_path: Option<&SmolStr>, |
650 | parent_module: Option<&Name>, | ||
639 | ) -> Result<FileId, RelativePathBuf> { | 651 | ) -> Result<FileId, RelativePathBuf> { |
640 | // FIXME: handle submodules of inline modules properly | ||
641 | let file_id = file_id.original_file(db); | 652 | let file_id = file_id.original_file(db); |
642 | let source_root_id = db.file_source_root(file_id); | 653 | let source_root_id = db.file_source_root(file_id); |
643 | let path = db.file_relative_path(file_id); | 654 | let path = db.file_relative_path(file_id); |
644 | let root = RelativePathBuf::default(); | 655 | let root = RelativePathBuf::default(); |
645 | let dir_path = path.parent().unwrap_or(&root); | 656 | let dir_path = path.parent().unwrap_or(&root); |
646 | let mod_name = path.file_stem().unwrap_or("unknown"); | 657 | let mod_name = path.file_stem().unwrap_or("unknown"); |
647 | let is_dir_owner = is_root || mod_name == "mod"; | 658 | |
648 | 659 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | |
649 | let file_mod = dir_path.join(format!("{}.rs", name)); | 660 | (Some(file_path), Some(parent_name)) => { |
650 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | 661 | let file_path = normalize_attribute_path(file_path); |
651 | let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); | 662 | let path = dir_path.join(format!("{}/{}", parent_name, file_path)).normalize(); |
652 | let mut candidates = ArrayVec::<[_; 3]>::new(); | 663 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(path)) |
653 | let file_attr_mod = attr_path.map(|file_path| { | 664 | } |
654 | let file_path = normalize_attribute_path(file_path); | 665 | (Some(file_path), None) => { |
655 | let file_attr_mod = dir_path.join(file_path.as_ref()).normalize(); | 666 | let file_path = normalize_attribute_path(file_path); |
656 | candidates.push(file_attr_mod.clone()); | 667 | let path = dir_path.join(file_path.as_ref()).normalize(); |
657 | 668 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | |
658 | file_attr_mod | 669 | } |
659 | }); | 670 | (None, Some(parent_name)) => { |
660 | if is_dir_owner { | 671 | let path = dir_path.join(format!("{}/{}.rs", parent_name, name)); |
661 | candidates.push(file_mod.clone()); | 672 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) |
662 | candidates.push(dir_mod); | 673 | } |
663 | } else { | 674 | _ => { |
664 | candidates.push(file_dir_mod.clone()); | 675 | let is_dir_owner = is_root || mod_name == "mod"; |
665 | }; | 676 | if is_dir_owner { |
666 | let sr = db.source_root(source_root_id); | 677 | 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(); | 678 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); |
668 | // FIXME: handle ambiguity | 679 | ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { |
669 | match points_to.next() { | 680 | file: file_mod, |
670 | Some(file_id) => Ok(file_id), | 681 | directory: dir_mod, |
671 | None => { | 682 | }) |
672 | if let Some(file_attr_mod) = file_attr_mod { | ||
673 | Err(file_attr_mod) | ||
674 | } else { | 683 | } else { |
675 | Err(if is_dir_owner { file_mod } else { file_dir_mod }) | 684 | let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); |
685 | ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) | ||
676 | } | 686 | } |
677 | } | 687 | } |
678 | } | 688 | }; |
689 | |||
690 | resolve_mode.resolve(db.source_root(source_root_id)) | ||
679 | } | 691 | } |
680 | 692 | ||
681 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | 693 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { |
@@ -693,6 +705,74 @@ fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | |||
693 | } | 705 | } |
694 | } | 706 | } |
695 | 707 | ||
708 | enum OutOfLineMode { | ||
709 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
710 | FileInDirectory(RelativePathBuf), | ||
711 | WithAttributePath(RelativePathBuf), | ||
712 | } | ||
713 | |||
714 | impl OutOfLineMode { | ||
715 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
716 | match self { | ||
717 | OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) { | ||
718 | None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), | ||
719 | file_id => resolve_find_result(file_id, file), | ||
720 | }, | ||
721 | OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), | ||
722 | OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), | ||
723 | } | ||
724 | } | ||
725 | } | ||
726 | |||
727 | enum InsideInlineModuleMode { | ||
728 | File(RelativePathBuf), | ||
729 | WithAttributePath(RelativePathBuf), | ||
730 | } | ||
731 | |||
732 | impl InsideInlineModuleMode { | ||
733 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
734 | match self { | ||
735 | InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), | ||
736 | InsideInlineModuleMode::WithAttributePath(path) => { | ||
737 | resolve_simple_path(source_root, path) | ||
738 | } | ||
739 | } | ||
740 | } | ||
741 | } | ||
742 | |||
743 | enum ResolutionMode { | ||
744 | OutOfLine(OutOfLineMode), | ||
745 | InsideInlineModule(InsideInlineModuleMode), | ||
746 | } | ||
747 | |||
748 | impl ResolutionMode { | ||
749 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
750 | use self::ResolutionMode::*; | ||
751 | |||
752 | match self { | ||
753 | OutOfLine(mode) => mode.resolve(source_root), | ||
754 | InsideInlineModule(mode) => mode.resolve(source_root), | ||
755 | } | ||
756 | } | ||
757 | } | ||
758 | |||
759 | fn resolve_simple_path( | ||
760 | source_root: Arc<SourceRoot>, | ||
761 | path: &RelativePathBuf, | ||
762 | ) -> Result<FileId, RelativePathBuf> { | ||
763 | resolve_find_result(source_root.files.get(path), path) | ||
764 | } | ||
765 | |||
766 | fn resolve_find_result( | ||
767 | file_id: Option<&FileId>, | ||
768 | path: &RelativePathBuf, | ||
769 | ) -> Result<FileId, RelativePathBuf> { | ||
770 | match file_id { | ||
771 | Some(file_id) => Ok(file_id.clone()), | ||
772 | None => Err(path.clone()), | ||
773 | } | ||
774 | } | ||
775 | |||
696 | #[cfg(test)] | 776 | #[cfg(test)] |
697 | mod tests { | 777 | mod tests { |
698 | use ra_db::SourceDatabase; | 778 | use ra_db::SourceDatabase; |