diff options
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 249 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/mod_resolution.rs | 186 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 121 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/mod_resolution.rs (renamed from crates/ra_hir/src/nameres/tests/mods.rs) | 0 |
6 files changed, 377 insertions, 194 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7da2dcdff..5af26f953 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,9 +1,5 @@ | |||
1 | use std::borrow::Cow; | 1 | use ra_db::FileId; |
2 | use std::sync::Arc; | 2 | use ra_syntax::ast; |
3 | |||
4 | use ra_db::{FileId, SourceRoot}; | ||
5 | use ra_syntax::{ast, SmolStr}; | ||
6 | use relative_path::RelativePathBuf; | ||
7 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
8 | use test_utils::tested_by; | 4 | use test_utils::tested_by; |
9 | 5 | ||
@@ -12,8 +8,10 @@ use crate::{ | |||
12 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, | 8 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, |
13 | name::MACRO_RULES, | 9 | name::MACRO_RULES, |
14 | nameres::{ | 10 | nameres::{ |
15 | diagnostics::DefDiagnostic, raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, | 11 | diagnostics::DefDiagnostic, |
16 | ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, | 12 | mod_resolution::{resolve_submodule, ParentModule}, |
13 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, | ||
14 | ReachedFixedPoint, Resolution, ResolveMode, | ||
17 | }, | 15 | }, |
18 | AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, | 16 | AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, |
19 | Struct, Trait, TypeAlias, Union, | 17 | Struct, Trait, TypeAlias, Union, |
@@ -157,11 +155,45 @@ where | |||
157 | // crate root, even if the parent modules is **not** visible. | 155 | // crate root, even if the parent modules is **not** visible. |
158 | if export { | 156 | if export { |
159 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 157 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); |
158 | |||
159 | // Exported macros are collected in crate level ready for | ||
160 | // glob import with `#[macro_use]`. | ||
161 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
160 | } | 162 | } |
161 | self.update(module_id, None, &[(name.clone(), def)]); | 163 | self.update(module_id, None, &[(name.clone(), def)]); |
162 | self.global_macro_scope.insert(name, macro_id); | 164 | self.global_macro_scope.insert(name, macro_id); |
163 | } | 165 | } |
164 | 166 | ||
167 | /// Import macros from `#[macro_use] extern crate`. | ||
168 | /// | ||
169 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
170 | fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { | ||
171 | log::debug!( | ||
172 | "importing macros from extern crate: {:?} ({:?})", | ||
173 | import, | ||
174 | self.def_map.edition, | ||
175 | ); | ||
176 | |||
177 | let res = self.def_map.resolve_name_in_extern_prelude( | ||
178 | &import | ||
179 | .path | ||
180 | .as_ident() | ||
181 | .expect("extern crate should have been desugared to one-element path"), | ||
182 | ); | ||
183 | |||
184 | if let Some(ModuleDef::Module(m)) = res.take_types() { | ||
185 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
186 | self.import_all_macros_exported(m); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | fn import_all_macros_exported(&mut self, module: Module) { | ||
191 | let item_map = self.db.crate_def_map(module.krate); | ||
192 | for (name, ¯o_id) in &item_map.exported_macros { | ||
193 | self.global_macro_scope.insert(name.clone(), macro_id); | ||
194 | } | ||
195 | } | ||
196 | |||
165 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 197 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
166 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 198 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
167 | let mut resolved = Vec::new(); | 199 | let mut resolved = Vec::new(); |
@@ -491,13 +523,31 @@ where | |||
491 | DB: DefDatabase, | 523 | DB: DefDatabase, |
492 | { | 524 | { |
493 | fn collect(&mut self, items: &[raw::RawItem]) { | 525 | fn collect(&mut self, items: &[raw::RawItem]) { |
526 | // Prelude module is always considered to be `#[macro_use]`. | ||
527 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | ||
528 | tested_by!(prelude_is_macro_use); | ||
529 | self.def_collector.import_all_macros_exported(prelude_module); | ||
530 | } | ||
531 | |||
532 | // This should be processed eagerly instead of deferred to resolving. | ||
533 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | ||
534 | // any other items. | ||
535 | for item in items { | ||
536 | if let raw::RawItem::Import(import_id) = *item { | ||
537 | let import = self.raw_items[import_id].clone(); | ||
538 | if import.is_extern_crate && import.is_macro_use { | ||
539 | self.def_collector.import_macros_from_extern_crate(&import); | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | |||
494 | for item in items { | 544 | for item in items { |
495 | match *item { | 545 | match *item { |
496 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 546 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), |
497 | raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( | 547 | raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( |
498 | self.module_id, | 548 | self.module_id, |
499 | import, | 549 | import_id, |
500 | self.raw_items[import].clone(), | 550 | self.raw_items[import_id].clone(), |
501 | )), | 551 | )), |
502 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), | 552 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), |
503 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 553 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
@@ -531,7 +581,7 @@ where | |||
531 | name, | 581 | name, |
532 | is_root, | 582 | is_root, |
533 | attr_path.as_ref(), | 583 | attr_path.as_ref(), |
534 | self.parent_module.as_ref(), | 584 | self.parent_module, |
535 | ) { | 585 | ) { |
536 | Ok(file_id) => { | 586 | Ok(file_id) => { |
537 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 587 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
@@ -642,180 +692,6 @@ fn is_macro_rules(path: &Path) -> bool { | |||
642 | path.as_ident() == Some(&MACRO_RULES) | 692 | path.as_ident() == Some(&MACRO_RULES) |
643 | } | 693 | } |
644 | 694 | ||
645 | fn resolve_submodule( | ||
646 | db: &impl DefDatabase, | ||
647 | file_id: HirFileId, | ||
648 | name: &Name, | ||
649 | is_root: bool, | ||
650 | attr_path: Option<&SmolStr>, | ||
651 | parent_module: Option<&ParentModule>, | ||
652 | ) -> Result<FileId, RelativePathBuf> { | ||
653 | let file_id = file_id.original_file(db); | ||
654 | let source_root_id = db.file_source_root(file_id); | ||
655 | let path = db.file_relative_path(file_id); | ||
656 | let root = RelativePathBuf::default(); | ||
657 | let dir_path = path.parent().unwrap_or(&root); | ||
658 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
659 | |||
660 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | ||
661 | (Some(file_path), Some(parent_module)) => { | ||
662 | let file_path = normalize_attribute_path(file_path); | ||
663 | match parent_module.attribute_path() { | ||
664 | Some(parent_module_attr_path) => { | ||
665 | let path = dir_path | ||
666 | .join(format!( | ||
667 | "{}/{}", | ||
668 | normalize_attribute_path(parent_module_attr_path), | ||
669 | file_path | ||
670 | )) | ||
671 | .normalize(); | ||
672 | ResolutionMode::InlineModuleWithAttributePath( | ||
673 | InsideInlineModuleMode::WithAttributePath(path), | ||
674 | ) | ||
675 | } | ||
676 | None => { | ||
677 | let path = | ||
678 | dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize(); | ||
679 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath( | ||
680 | path, | ||
681 | )) | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | (None, Some(parent_module)) => match parent_module.attribute_path() { | ||
686 | Some(parent_module_attr_path) => { | ||
687 | let path = dir_path.join(format!( | ||
688 | "{}/{}.rs", | ||
689 | normalize_attribute_path(parent_module_attr_path), | ||
690 | name | ||
691 | )); | ||
692 | ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) | ||
693 | } | ||
694 | None => { | ||
695 | let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); | ||
696 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
697 | } | ||
698 | }, | ||
699 | (Some(file_path), None) => { | ||
700 | let file_path = normalize_attribute_path(file_path); | ||
701 | let path = dir_path.join(file_path.as_ref()).normalize(); | ||
702 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | ||
703 | } | ||
704 | _ => { | ||
705 | let is_dir_owner = is_root || mod_name == "mod"; | ||
706 | if is_dir_owner { | ||
707 | let file_mod = dir_path.join(format!("{}.rs", name)); | ||
708 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | ||
709 | ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { | ||
710 | file: file_mod, | ||
711 | directory: dir_mod, | ||
712 | }) | ||
713 | } else { | ||
714 | let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); | ||
715 | ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) | ||
716 | } | ||
717 | } | ||
718 | }; | ||
719 | |||
720 | resolve_mode.resolve(db.source_root(source_root_id)) | ||
721 | } | ||
722 | |||
723 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | ||
724 | let current_dir = "./"; | ||
725 | let windows_path_separator = r#"\"#; | ||
726 | let current_dir_normalize = if file_path.starts_with(current_dir) { | ||
727 | &file_path[current_dir.len()..] | ||
728 | } else { | ||
729 | file_path.as_str() | ||
730 | }; | ||
731 | if current_dir_normalize.contains(windows_path_separator) { | ||
732 | Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/")) | ||
733 | } else { | ||
734 | Cow::Borrowed(current_dir_normalize) | ||
735 | } | ||
736 | } | ||
737 | |||
738 | enum OutOfLineMode { | ||
739 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
740 | FileInDirectory(RelativePathBuf), | ||
741 | WithAttributePath(RelativePathBuf), | ||
742 | } | ||
743 | |||
744 | impl OutOfLineMode { | ||
745 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
746 | match self { | ||
747 | OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) { | ||
748 | None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), | ||
749 | file_id => resolve_find_result(file_id, file), | ||
750 | }, | ||
751 | OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), | ||
752 | OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | |||
757 | enum InsideInlineModuleMode { | ||
758 | File(RelativePathBuf), | ||
759 | WithAttributePath(RelativePathBuf), | ||
760 | } | ||
761 | |||
762 | impl InsideInlineModuleMode { | ||
763 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
764 | match self { | ||
765 | InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), | ||
766 | InsideInlineModuleMode::WithAttributePath(path) => { | ||
767 | resolve_simple_path(source_root, path) | ||
768 | } | ||
769 | } | ||
770 | } | ||
771 | } | ||
772 | |||
773 | enum ResolutionMode { | ||
774 | OutOfLine(OutOfLineMode), | ||
775 | InsideInlineModule(InsideInlineModuleMode), | ||
776 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
777 | } | ||
778 | |||
779 | impl ResolutionMode { | ||
780 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
781 | use self::ResolutionMode::*; | ||
782 | |||
783 | match self { | ||
784 | OutOfLine(mode) => mode.resolve(source_root), | ||
785 | InsideInlineModule(mode) => mode.resolve(source_root), | ||
786 | InlineModuleWithAttributePath(mode) => mode.resolve(source_root), | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | |||
791 | fn resolve_simple_path( | ||
792 | source_root: Arc<SourceRoot>, | ||
793 | path: &RelativePathBuf, | ||
794 | ) -> Result<FileId, RelativePathBuf> { | ||
795 | resolve_find_result(source_root.files.get(path), path) | ||
796 | } | ||
797 | |||
798 | fn resolve_find_result( | ||
799 | file_id: Option<&FileId>, | ||
800 | path: &RelativePathBuf, | ||
801 | ) -> Result<FileId, RelativePathBuf> { | ||
802 | match file_id { | ||
803 | Some(file_id) => Ok(file_id.clone()), | ||
804 | None => Err(path.clone()), | ||
805 | } | ||
806 | } | ||
807 | |||
808 | struct ParentModule<'a> { | ||
809 | name: &'a Name, | ||
810 | attr_path: Option<&'a SmolStr>, | ||
811 | } | ||
812 | |||
813 | impl<'a> ParentModule<'a> { | ||
814 | pub fn attribute_path(&self) -> Option<&SmolStr> { | ||
815 | self.attr_path.filter(|p| !p.is_empty()) | ||
816 | } | ||
817 | } | ||
818 | |||
819 | #[cfg(test)] | 695 | #[cfg(test)] |
820 | mod tests { | 696 | mod tests { |
821 | use ra_db::SourceDatabase; | 697 | use ra_db::SourceDatabase; |
@@ -860,6 +736,7 @@ mod tests { | |||
860 | root, | 736 | root, |
861 | modules, | 737 | modules, |
862 | poison_macros: FxHashSet::default(), | 738 | poison_macros: FxHashSet::default(), |
739 | exported_macros: FxHashMap::default(), | ||
863 | diagnostics: Vec::new(), | 740 | diagnostics: Vec::new(), |
864 | } | 741 | } |
865 | }; | 742 | }; |
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs new file mode 100644 index 000000000..918c9591f --- /dev/null +++ b/crates/ra_hir/src/nameres/mod_resolution.rs | |||
@@ -0,0 +1,186 @@ | |||
1 | //! This module resolves `mod foo;` declaration to file. | ||
2 | |||
3 | use std::{borrow::Cow, sync::Arc}; | ||
4 | |||
5 | use ra_db::{FileId, SourceRoot}; | ||
6 | use ra_syntax::SmolStr; | ||
7 | use relative_path::RelativePathBuf; | ||
8 | |||
9 | use crate::{DefDatabase, HirFileId, Name}; | ||
10 | |||
11 | #[derive(Clone, Copy)] | ||
12 | pub(super) struct ParentModule<'a> { | ||
13 | pub(super) name: &'a Name, | ||
14 | pub(super) attr_path: Option<&'a SmolStr>, | ||
15 | } | ||
16 | |||
17 | impl<'a> ParentModule<'a> { | ||
18 | fn attribute_path(&self) -> Option<&SmolStr> { | ||
19 | self.attr_path.filter(|p| !p.is_empty()) | ||
20 | } | ||
21 | } | ||
22 | |||
23 | pub(super) fn resolve_submodule( | ||
24 | db: &impl DefDatabase, | ||
25 | file_id: HirFileId, | ||
26 | name: &Name, | ||
27 | is_root: bool, | ||
28 | attr_path: Option<&SmolStr>, | ||
29 | parent_module: Option<ParentModule<'_>>, | ||
30 | ) -> Result<FileId, RelativePathBuf> { | ||
31 | let file_id = file_id.original_file(db); | ||
32 | let source_root_id = db.file_source_root(file_id); | ||
33 | let path = db.file_relative_path(file_id); | ||
34 | let root = RelativePathBuf::default(); | ||
35 | let dir_path = path.parent().unwrap_or(&root); | ||
36 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
37 | |||
38 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | ||
39 | (Some(file_path), Some(parent_module)) => { | ||
40 | let file_path = normalize_attribute_path(file_path); | ||
41 | match parent_module.attribute_path() { | ||
42 | Some(parent_module_attr_path) => { | ||
43 | let path = dir_path | ||
44 | .join(format!( | ||
45 | "{}/{}", | ||
46 | normalize_attribute_path(parent_module_attr_path), | ||
47 | file_path | ||
48 | )) | ||
49 | .normalize(); | ||
50 | ResolutionMode::InlineModuleWithAttributePath( | ||
51 | InsideInlineModuleMode::WithAttributePath(path), | ||
52 | ) | ||
53 | } | ||
54 | None => { | ||
55 | let path = | ||
56 | dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize(); | ||
57 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath( | ||
58 | path, | ||
59 | )) | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | (None, Some(parent_module)) => match parent_module.attribute_path() { | ||
64 | Some(parent_module_attr_path) => { | ||
65 | let path = dir_path.join(format!( | ||
66 | "{}/{}.rs", | ||
67 | normalize_attribute_path(parent_module_attr_path), | ||
68 | name | ||
69 | )); | ||
70 | ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) | ||
71 | } | ||
72 | None => { | ||
73 | let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); | ||
74 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
75 | } | ||
76 | }, | ||
77 | (Some(file_path), None) => { | ||
78 | let file_path = normalize_attribute_path(file_path); | ||
79 | let path = dir_path.join(file_path.as_ref()).normalize(); | ||
80 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | ||
81 | } | ||
82 | (None, None) => { | ||
83 | let is_dir_owner = is_root || mod_name == "mod"; | ||
84 | if is_dir_owner { | ||
85 | let file_mod = dir_path.join(format!("{}.rs", name)); | ||
86 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | ||
87 | ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { | ||
88 | file: file_mod, | ||
89 | directory: dir_mod, | ||
90 | }) | ||
91 | } else { | ||
92 | let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); | ||
93 | ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) | ||
94 | } | ||
95 | } | ||
96 | }; | ||
97 | |||
98 | resolve_mode.resolve(db.source_root(source_root_id)) | ||
99 | } | ||
100 | |||
101 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | ||
102 | let current_dir = "./"; | ||
103 | let windows_path_separator = r#"\"#; | ||
104 | let current_dir_normalize = if file_path.starts_with(current_dir) { | ||
105 | &file_path[current_dir.len()..] | ||
106 | } else { | ||
107 | file_path.as_str() | ||
108 | }; | ||
109 | if current_dir_normalize.contains(windows_path_separator) { | ||
110 | Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/")) | ||
111 | } else { | ||
112 | Cow::Borrowed(current_dir_normalize) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | enum OutOfLineMode { | ||
117 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
118 | FileInDirectory(RelativePathBuf), | ||
119 | WithAttributePath(RelativePathBuf), | ||
120 | } | ||
121 | |||
122 | impl OutOfLineMode { | ||
123 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
124 | match self { | ||
125 | OutOfLineMode::RootOrModRs { file, directory } => { | ||
126 | match source_root.file_by_relative_path(file) { | ||
127 | None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), | ||
128 | file_id => resolve_find_result(file_id, file), | ||
129 | } | ||
130 | } | ||
131 | OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), | ||
132 | OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | enum InsideInlineModuleMode { | ||
138 | File(RelativePathBuf), | ||
139 | WithAttributePath(RelativePathBuf), | ||
140 | } | ||
141 | |||
142 | impl InsideInlineModuleMode { | ||
143 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
144 | match self { | ||
145 | InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), | ||
146 | InsideInlineModuleMode::WithAttributePath(path) => { | ||
147 | resolve_simple_path(source_root, path) | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | enum ResolutionMode { | ||
154 | OutOfLine(OutOfLineMode), | ||
155 | InsideInlineModule(InsideInlineModuleMode), | ||
156 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
157 | } | ||
158 | |||
159 | impl ResolutionMode { | ||
160 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
161 | use self::ResolutionMode::*; | ||
162 | |||
163 | match self { | ||
164 | OutOfLine(mode) => mode.resolve(source_root), | ||
165 | InsideInlineModule(mode) => mode.resolve(source_root), | ||
166 | InlineModuleWithAttributePath(mode) => mode.resolve(source_root), | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | fn resolve_simple_path( | ||
172 | source_root: Arc<SourceRoot>, | ||
173 | path: &RelativePathBuf, | ||
174 | ) -> Result<FileId, RelativePathBuf> { | ||
175 | resolve_find_result(source_root.file_by_relative_path(path), path) | ||
176 | } | ||
177 | |||
178 | fn resolve_find_result( | ||
179 | file_id: Option<FileId>, | ||
180 | path: &RelativePathBuf, | ||
181 | ) -> Result<FileId, RelativePathBuf> { | ||
182 | match file_id { | ||
183 | Some(file_id) => Ok(file_id.clone()), | ||
184 | None => Err(path.clone()), | ||
185 | } | ||
186 | } | ||
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 2f973359f..129b047eb 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -154,6 +154,7 @@ pub struct ImportData { | |||
154 | pub(super) is_glob: bool, | 154 | pub(super) is_glob: bool, |
155 | pub(super) is_prelude: bool, | 155 | pub(super) is_prelude: bool, |
156 | pub(super) is_extern_crate: bool, | 156 | pub(super) is_extern_crate: bool, |
157 | pub(super) is_macro_use: bool, | ||
157 | } | 158 | } |
158 | 159 | ||
159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 160 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -293,8 +294,14 @@ impl RawItemsCollector { | |||
293 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 294 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
294 | 295 | ||
295 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { | 296 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { |
296 | let import_data = | 297 | let import_data = ImportData { |
297 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; | 298 | path, |
299 | alias, | ||
300 | is_glob, | ||
301 | is_prelude, | ||
302 | is_extern_crate: false, | ||
303 | is_macro_use: false, | ||
304 | }; | ||
298 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 305 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); |
299 | }) | 306 | }) |
300 | } | 307 | } |
@@ -307,12 +314,14 @@ impl RawItemsCollector { | |||
307 | if let Some(name_ref) = extern_crate.name_ref() { | 314 | if let Some(name_ref) = extern_crate.name_ref() { |
308 | let path = Path::from_name_ref(&name_ref); | 315 | let path = Path::from_name_ref(&name_ref); |
309 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 316 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
317 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
310 | let import_data = ImportData { | 318 | let import_data = ImportData { |
311 | path, | 319 | path, |
312 | alias, | 320 | alias, |
313 | is_glob: false, | 321 | is_glob: false, |
314 | is_prelude: false, | 322 | is_prelude: false, |
315 | is_extern_crate: true, | 323 | is_extern_crate: true, |
324 | is_macro_use, | ||
316 | }; | 325 | }; |
317 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); | 326 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); |
318 | } | 327 | } |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index c1dbad283..4ff897ca5 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -2,7 +2,7 @@ mod macros; | |||
2 | mod globs; | 2 | mod globs; |
3 | mod incremental; | 3 | mod incremental; |
4 | mod primitives; | 4 | mod primitives; |
5 | mod mods; | 5 | mod mod_resolution; |
6 | 6 | ||
7 | use std::sync::Arc; | 7 | use std::sync::Arc; |
8 | 8 | ||
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 631df2cef..aece1515b 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -99,14 +99,14 @@ fn macro_rules_from_other_crates_are_visible() { | |||
99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | 99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { |
100 | let map = def_map_with_crate_graph( | 100 | let map = def_map_with_crate_graph( |
101 | " | 101 | " |
102 | //- /main.rs | 102 | //- /main.rs |
103 | macro_rules! baz { | 103 | macro_rules! baz { |
104 | () => { | 104 | () => { |
105 | use foo::bar; | 105 | use foo::bar; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | foo!(); | 109 | foo!(); |
110 | bar!(); | 110 | bar!(); |
111 | baz!(); | 111 | baz!(); |
112 | 112 | ||
@@ -114,7 +114,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
114 | #[macro_export] | 114 | #[macro_export] |
115 | macro_rules! foo { | 115 | macro_rules! foo { |
116 | () => { | 116 | () => { |
117 | struct Foo { field: u32 } | 117 | struct Foo { field: u32 } |
118 | } | 118 | } |
119 | } | 119 | } |
120 | #[macro_export] | 120 | #[macro_export] |
@@ -137,3 +137,114 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
137 | ⋮foo: m | 137 | ⋮foo: m |
138 | "###); | 138 | "###); |
139 | } | 139 | } |
140 | |||
141 | #[test] | ||
142 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | ||
143 | covers!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
144 | let map = def_map_with_crate_graph( | ||
145 | " | ||
146 | //- /main.rs | ||
147 | structs!(Foo); | ||
148 | structs_priv!(Bar); | ||
149 | structs_not_exported!(MacroNotResolved1); | ||
150 | crate::structs!(MacroNotResolved2); | ||
151 | |||
152 | mod bar; | ||
153 | |||
154 | #[macro_use] | ||
155 | extern crate foo; | ||
156 | |||
157 | //- /bar.rs | ||
158 | structs!(Baz); | ||
159 | crate::structs!(MacroNotResolved3); | ||
160 | |||
161 | //- /lib.rs | ||
162 | #[macro_export] | ||
163 | macro_rules! structs { | ||
164 | ($i:ident) => { struct $i; } | ||
165 | } | ||
166 | |||
167 | macro_rules! structs_not_exported { | ||
168 | ($i:ident) => { struct $i; } | ||
169 | } | ||
170 | |||
171 | mod priv_mod { | ||
172 | #[macro_export] | ||
173 | macro_rules! structs_priv { | ||
174 | ($i:ident) => { struct $i; } | ||
175 | } | ||
176 | } | ||
177 | ", | ||
178 | crate_graph! { | ||
179 | "main": ("/main.rs", ["foo"]), | ||
180 | "foo": ("/lib.rs", []), | ||
181 | }, | ||
182 | ); | ||
183 | assert_snapshot!(map, @r###" | ||
184 | ⋮crate | ||
185 | ⋮Bar: t v | ||
186 | ⋮Foo: t v | ||
187 | ⋮bar: t | ||
188 | ⋮foo: t | ||
189 | ⋮ | ||
190 | ⋮crate::bar | ||
191 | ⋮Baz: t v | ||
192 | "###); | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn prelude_is_macro_use() { | ||
197 | covers!(prelude_is_macro_use); | ||
198 | let map = def_map_with_crate_graph( | ||
199 | " | ||
200 | //- /main.rs | ||
201 | structs!(Foo); | ||
202 | structs_priv!(Bar); | ||
203 | structs_outside!(Out); | ||
204 | crate::structs!(MacroNotResolved2); | ||
205 | |||
206 | mod bar; | ||
207 | |||
208 | //- /bar.rs | ||
209 | structs!(Baz); | ||
210 | crate::structs!(MacroNotResolved3); | ||
211 | |||
212 | //- /lib.rs | ||
213 | #[prelude_import] | ||
214 | use self::prelude::*; | ||
215 | |||
216 | mod prelude { | ||
217 | #[macro_export] | ||
218 | macro_rules! structs { | ||
219 | ($i:ident) => { struct $i; } | ||
220 | } | ||
221 | |||
222 | mod priv_mod { | ||
223 | #[macro_export] | ||
224 | macro_rules! structs_priv { | ||
225 | ($i:ident) => { struct $i; } | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | #[macro_export] | ||
231 | macro_rules! structs_outside { | ||
232 | ($i:ident) => { struct $i; } | ||
233 | } | ||
234 | ", | ||
235 | crate_graph! { | ||
236 | "main": ("/main.rs", ["foo"]), | ||
237 | "foo": ("/lib.rs", []), | ||
238 | }, | ||
239 | ); | ||
240 | assert_snapshot!(map, @r###" | ||
241 | ⋮crate | ||
242 | ⋮Bar: t v | ||
243 | ⋮Foo: t v | ||
244 | ⋮Out: t v | ||
245 | ⋮bar: t | ||
246 | ⋮ | ||
247 | ⋮crate::bar | ||
248 | ⋮Baz: t v | ||
249 | "###); | ||
250 | } | ||
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs index 4f8398460..4f8398460 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs | |||