aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/collector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs148
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 @@
1use std::borrow::Cow; 1use std::borrow::Cow;
2use std::sync::Arc;
2 3
3use arrayvec::ArrayVec; 4use ra_db::{FileId, SourceRoot};
4use ra_db::FileId;
5use ra_syntax::{ast, SmolStr}; 5use ra_syntax::{ast, SmolStr};
6use relative_path::RelativePathBuf; 6use relative_path::RelativePathBuf;
7use rustc_hash::FxHashMap; 7use 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>>
482where 482where
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
681fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { 683fn 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
698enum OutOfLineMode {
699 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
700 FileInDirectory(RelativePathBuf),
701 WithAttributePath(RelativePathBuf),
702}
703
704impl 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
717enum InsideInlineModuleMode {
718 File(RelativePathBuf),
719 WithAttributePath(RelativePathBuf),
720}
721
722impl 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
733enum ResolutionMode {
734 OutOfLine(OutOfLineMode),
735 InsideInlineModule(InsideInlineModuleMode),
736}
737
738impl 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
749fn 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
756fn 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)]
697mod tests { 767mod tests {
698 use ra_db::SourceDatabase; 768 use ra_db::SourceDatabase;