aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs249
-rw-r--r--crates/ra_hir/src/nameres/mod_resolution.rs186
-rw-r--r--crates/ra_hir/src/nameres/raw.rs13
-rw-r--r--crates/ra_hir/src/nameres/tests.rs2
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs121
-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 @@
1use std::borrow::Cow; 1use ra_db::FileId;
2use std::sync::Arc; 2use ra_syntax::ast;
3
4use ra_db::{FileId, SourceRoot};
5use ra_syntax::{ast, SmolStr};
6use relative_path::RelativePathBuf;
7use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
8use test_utils::tested_by; 4use 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, &macro_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
645fn 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
723fn 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
738enum OutOfLineMode {
739 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
740 FileInDirectory(RelativePathBuf),
741 WithAttributePath(RelativePathBuf),
742}
743
744impl 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
757enum InsideInlineModuleMode {
758 File(RelativePathBuf),
759 WithAttributePath(RelativePathBuf),
760}
761
762impl 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
773enum ResolutionMode {
774 OutOfLine(OutOfLineMode),
775 InsideInlineModule(InsideInlineModuleMode),
776 InlineModuleWithAttributePath(InsideInlineModuleMode),
777}
778
779impl 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
791fn 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
798fn 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
808struct ParentModule<'a> {
809 name: &'a Name,
810 attr_path: Option<&'a SmolStr>,
811}
812
813impl<'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)]
820mod tests { 696mod 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
3use std::{borrow::Cow, sync::Arc};
4
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::SmolStr;
7use relative_path::RelativePathBuf;
8
9use crate::{DefDatabase, HirFileId, Name};
10
11#[derive(Clone, Copy)]
12pub(super) struct ParentModule<'a> {
13 pub(super) name: &'a Name,
14 pub(super) attr_path: Option<&'a SmolStr>,
15}
16
17impl<'a> ParentModule<'a> {
18 fn attribute_path(&self) -> Option<&SmolStr> {
19 self.attr_path.filter(|p| !p.is_empty())
20 }
21}
22
23pub(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
101fn 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
116enum OutOfLineMode {
117 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
118 FileInDirectory(RelativePathBuf),
119 WithAttributePath(RelativePathBuf),
120}
121
122impl 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
137enum InsideInlineModuleMode {
138 File(RelativePathBuf),
139 WithAttributePath(RelativePathBuf),
140}
141
142impl 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
153enum ResolutionMode {
154 OutOfLine(OutOfLineMode),
155 InsideInlineModule(InsideInlineModuleMode),
156 InlineModuleWithAttributePath(InsideInlineModuleMode),
157}
158
159impl 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
171fn 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
178fn 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;
2mod globs; 2mod globs;
3mod incremental; 3mod incremental;
4mod primitives; 4mod primitives;
5mod mods; 5mod mod_resolution;
6 6
7use std::sync::Arc; 7use 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() {
99fn unexpanded_macro_should_expand_by_fixedpoint_loop() { 99fn 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]
142fn 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]
196fn 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