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/src/nameres/collector.rs | |
parent | de278d164906d6d29974790c5a4db28303692484 (diff) |
Added resolve modules inside inline module
#1510
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 148 |
1 files changed, 109 insertions, 39 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; |