diff options
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 79 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 49 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/globs.rs | 90 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/simple.rs | 46 |
4 files changed, 244 insertions, 20 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index c81b966c3..4d446c707 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -4,14 +4,27 @@ | |||
4 | use hir_expand::name::Name; | 4 | use hir_expand::name::Name; |
5 | use once_cell::sync::Lazy; | 5 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | 6 | use ra_db::CrateId; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::{FxHashMap, FxHashSet}; |
8 | use test_utils::mark; | 8 | use test_utils::mark; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 11 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
12 | Lookup, MacroDefId, ModuleDefId, TraitId, | 12 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | #[derive(Copy, Clone)] | ||
16 | pub(crate) enum ImportType { | ||
17 | Glob, | ||
18 | Named, | ||
19 | } | ||
20 | |||
21 | #[derive(Debug, Default)] | ||
22 | pub struct PerNsGlobImports { | ||
23 | types: FxHashSet<(LocalModuleId, Name)>, | ||
24 | values: FxHashSet<(LocalModuleId, Name)>, | ||
25 | macros: FxHashSet<(LocalModuleId, Name)>, | ||
26 | } | ||
27 | |||
15 | #[derive(Debug, Default, PartialEq, Eq)] | 28 | #[derive(Debug, Default, PartialEq, Eq)] |
16 | pub struct ItemScope { | 29 | pub struct ItemScope { |
17 | visible: FxHashMap<Name, PerNs>, | 30 | visible: FxHashMap<Name, PerNs>, |
@@ -127,16 +140,62 @@ impl ItemScope { | |||
127 | let mut changed = false; | 140 | let mut changed = false; |
128 | let existing = self.visible.entry(name).or_default(); | 141 | let existing = self.visible.entry(name).or_default(); |
129 | 142 | ||
143 | if existing.types.is_none() && def.types.is_some() { | ||
144 | existing.types = def.types; | ||
145 | changed = true; | ||
146 | } | ||
147 | |||
148 | if existing.values.is_none() && def.values.is_some() { | ||
149 | existing.values = def.values; | ||
150 | changed = true; | ||
151 | } | ||
152 | |||
153 | if existing.macros.is_none() && def.macros.is_some() { | ||
154 | existing.macros = def.macros; | ||
155 | changed = true; | ||
156 | } | ||
157 | |||
158 | changed | ||
159 | } | ||
160 | |||
161 | pub(crate) fn push_res_with_import( | ||
162 | &mut self, | ||
163 | glob_imports: &mut PerNsGlobImports, | ||
164 | lookup: (LocalModuleId, Name), | ||
165 | def: PerNs, | ||
166 | def_import_type: ImportType, | ||
167 | ) -> bool { | ||
168 | let mut changed = false; | ||
169 | let existing = self.visible.entry(lookup.1.clone()).or_default(); | ||
170 | |||
130 | macro_rules! check_changed { | 171 | macro_rules! check_changed { |
131 | ($changed:ident, $existing:expr, $def:expr) => { | 172 | ( |
132 | match ($existing, $def) { | 173 | $changed:ident, |
174 | ( $existing:ident / $def:ident ) . $field:ident, | ||
175 | $glob_imports:ident [ $lookup:ident ], | ||
176 | $def_import_type:ident | ||
177 | ) => { | ||
178 | match ($existing.$field, $def.$field) { | ||
133 | (None, Some(_)) => { | 179 | (None, Some(_)) => { |
134 | $existing = $def; | 180 | match $def_import_type { |
181 | ImportType::Glob => { | ||
182 | $glob_imports.$field.insert($lookup.clone()); | ||
183 | } | ||
184 | ImportType::Named => { | ||
185 | $glob_imports.$field.remove(&$lookup); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | $existing.$field = $def.$field; | ||
135 | $changed = true; | 190 | $changed = true; |
136 | } | 191 | } |
137 | (Some(e), Some(d)) if e.0 != d.0 => { | 192 | (Some(_), Some(_)) |
193 | if $glob_imports.$field.contains(&$lookup) | ||
194 | && matches!($def_import_type, ImportType::Named) => | ||
195 | { | ||
138 | mark::hit!(import_shadowed); | 196 | mark::hit!(import_shadowed); |
139 | $existing = $def; | 197 | $glob_imports.$field.remove(&$lookup); |
198 | $existing.$field = $def.$field; | ||
140 | $changed = true; | 199 | $changed = true; |
141 | } | 200 | } |
142 | _ => {} | 201 | _ => {} |
@@ -144,9 +203,9 @@ impl ItemScope { | |||
144 | }; | 203 | }; |
145 | } | 204 | } |
146 | 205 | ||
147 | check_changed!(changed, existing.types, def.types); | 206 | check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); |
148 | check_changed!(changed, existing.values, def.values); | 207 | check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); |
149 | check_changed!(changed, existing.macros, def.macros); | 208 | check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); |
150 | 209 | ||
151 | changed | 210 | changed |
152 | } | 211 | } |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 2ced4f66b..a35ac1024 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -20,6 +20,7 @@ use test_utils::mark; | |||
20 | use crate::{ | 20 | use crate::{ |
21 | attr::Attrs, | 21 | attr::Attrs, |
22 | db::DefDatabase, | 22 | db::DefDatabase, |
23 | item_scope::{ImportType, PerNsGlobImports}, | ||
23 | item_tree::{ | 24 | item_tree::{ |
24 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, | 25 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind, |
25 | }, | 26 | }, |
@@ -80,6 +81,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr | |||
80 | mod_dirs: FxHashMap::default(), | 81 | mod_dirs: FxHashMap::default(), |
81 | cfg_options, | 82 | cfg_options, |
82 | proc_macros, | 83 | proc_macros, |
84 | from_glob_import: Default::default(), | ||
83 | }; | 85 | }; |
84 | collector.collect(); | 86 | collector.collect(); |
85 | collector.finish() | 87 | collector.finish() |
@@ -186,6 +188,7 @@ struct DefCollector<'a> { | |||
186 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 188 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
187 | cfg_options: &'a CfgOptions, | 189 | cfg_options: &'a CfgOptions, |
188 | proc_macros: Vec<(Name, ProcMacroExpander)>, | 190 | proc_macros: Vec<(Name, ProcMacroExpander)>, |
191 | from_glob_import: PerNsGlobImports, | ||
189 | } | 192 | } |
190 | 193 | ||
191 | impl DefCollector<'_> { | 194 | impl DefCollector<'_> { |
@@ -305,6 +308,7 @@ impl DefCollector<'_> { | |||
305 | self.def_map.root, | 308 | self.def_map.root, |
306 | &[(name, PerNs::macros(macro_, Visibility::Public))], | 309 | &[(name, PerNs::macros(macro_, Visibility::Public))], |
307 | Visibility::Public, | 310 | Visibility::Public, |
311 | ImportType::Named, | ||
308 | ); | 312 | ); |
309 | } | 313 | } |
310 | } | 314 | } |
@@ -330,6 +334,7 @@ impl DefCollector<'_> { | |||
330 | self.def_map.root, | 334 | self.def_map.root, |
331 | &[(name, PerNs::macros(macro_, Visibility::Public))], | 335 | &[(name, PerNs::macros(macro_, Visibility::Public))], |
332 | Visibility::Public, | 336 | Visibility::Public, |
337 | ImportType::Named, | ||
333 | ); | 338 | ); |
334 | } | 339 | } |
335 | 340 | ||
@@ -383,7 +388,6 @@ impl DefCollector<'_> { | |||
383 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 388 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
384 | for mut directive in imports { | 389 | for mut directive in imports { |
385 | directive.status = self.resolve_import(directive.module_id, &directive.import); | 390 | directive.status = self.resolve_import(directive.module_id, &directive.import); |
386 | |||
387 | match directive.status { | 391 | match directive.status { |
388 | PartialResolvedImport::Indeterminate(_) => { | 392 | PartialResolvedImport::Indeterminate(_) => { |
389 | self.record_resolved_import(&directive); | 393 | self.record_resolved_import(&directive); |
@@ -477,7 +481,7 @@ impl DefCollector<'_> { | |||
477 | .filter(|(_, res)| !res.is_none()) | 481 | .filter(|(_, res)| !res.is_none()) |
478 | .collect::<Vec<_>>(); | 482 | .collect::<Vec<_>>(); |
479 | 483 | ||
480 | self.update(module_id, &items, vis); | 484 | self.update(module_id, &items, vis, ImportType::Glob); |
481 | } else { | 485 | } else { |
482 | // glob import from same crate => we do an initial | 486 | // glob import from same crate => we do an initial |
483 | // import, and then need to propagate any further | 487 | // import, and then need to propagate any further |
@@ -499,7 +503,7 @@ impl DefCollector<'_> { | |||
499 | .filter(|(_, res)| !res.is_none()) | 503 | .filter(|(_, res)| !res.is_none()) |
500 | .collect::<Vec<_>>(); | 504 | .collect::<Vec<_>>(); |
501 | 505 | ||
502 | self.update(module_id, &items, vis); | 506 | self.update(module_id, &items, vis, ImportType::Glob); |
503 | // record the glob import in case we add further items | 507 | // record the glob import in case we add further items |
504 | let glob = self.glob_imports.entry(m.local_id).or_default(); | 508 | let glob = self.glob_imports.entry(m.local_id).or_default(); |
505 | if !glob.iter().any(|(mid, _)| *mid == module_id) { | 509 | if !glob.iter().any(|(mid, _)| *mid == module_id) { |
@@ -529,7 +533,7 @@ impl DefCollector<'_> { | |||
529 | (name, res) | 533 | (name, res) |
530 | }) | 534 | }) |
531 | .collect::<Vec<_>>(); | 535 | .collect::<Vec<_>>(); |
532 | self.update(module_id, &resolutions, vis); | 536 | self.update(module_id, &resolutions, vis, ImportType::Glob); |
533 | } | 537 | } |
534 | Some(d) => { | 538 | Some(d) => { |
535 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | 539 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); |
@@ -555,15 +559,21 @@ impl DefCollector<'_> { | |||
555 | } | 559 | } |
556 | } | 560 | } |
557 | 561 | ||
558 | self.update(module_id, &[(name, def)], vis); | 562 | self.update(module_id, &[(name, def)], vis, ImportType::Named); |
559 | } | 563 | } |
560 | None => mark::hit!(bogus_paths), | 564 | None => mark::hit!(bogus_paths), |
561 | } | 565 | } |
562 | } | 566 | } |
563 | } | 567 | } |
564 | 568 | ||
565 | fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)], vis: Visibility) { | 569 | fn update( |
566 | self.update_recursive(module_id, resolutions, vis, 0) | 570 | &mut self, |
571 | module_id: LocalModuleId, | ||
572 | resolutions: &[(Name, PerNs)], | ||
573 | vis: Visibility, | ||
574 | import_type: ImportType, | ||
575 | ) { | ||
576 | self.update_recursive(module_id, resolutions, vis, import_type, 0) | ||
567 | } | 577 | } |
568 | 578 | ||
569 | fn update_recursive( | 579 | fn update_recursive( |
@@ -573,6 +583,7 @@ impl DefCollector<'_> { | |||
573 | // All resolutions are imported with this visibility; the visibilies in | 583 | // All resolutions are imported with this visibility; the visibilies in |
574 | // the `PerNs` values are ignored and overwritten | 584 | // the `PerNs` values are ignored and overwritten |
575 | vis: Visibility, | 585 | vis: Visibility, |
586 | import_type: ImportType, | ||
576 | depth: usize, | 587 | depth: usize, |
577 | ) { | 588 | ) { |
578 | if depth > 100 { | 589 | if depth > 100 { |
@@ -582,7 +593,12 @@ impl DefCollector<'_> { | |||
582 | let scope = &mut self.def_map.modules[module_id].scope; | 593 | let scope = &mut self.def_map.modules[module_id].scope; |
583 | let mut changed = false; | 594 | let mut changed = false; |
584 | for (name, res) in resolutions { | 595 | for (name, res) in resolutions { |
585 | changed |= scope.push_res(name.clone(), res.with_visibility(vis)); | 596 | changed |= scope.push_res_with_import( |
597 | &mut self.from_glob_import, | ||
598 | (module_id, name.clone()), | ||
599 | res.with_visibility(vis), | ||
600 | import_type, | ||
601 | ); | ||
586 | } | 602 | } |
587 | 603 | ||
588 | if !changed { | 604 | if !changed { |
@@ -601,7 +617,13 @@ impl DefCollector<'_> { | |||
601 | if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) { | 617 | if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) { |
602 | continue; | 618 | continue; |
603 | } | 619 | } |
604 | self.update_recursive(glob_importing_module, resolutions, glob_import_vis, depth + 1); | 620 | self.update_recursive( |
621 | glob_importing_module, | ||
622 | resolutions, | ||
623 | glob_import_vis, | ||
624 | ImportType::Glob, | ||
625 | depth + 1, | ||
626 | ); | ||
605 | } | 627 | } |
606 | } | 628 | } |
607 | 629 | ||
@@ -923,6 +945,7 @@ impl ModCollector<'_, '_> { | |||
923 | self.module_id, | 945 | self.module_id, |
924 | &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], | 946 | &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], |
925 | vis, | 947 | vis, |
948 | ImportType::Named, | ||
926 | ) | 949 | ) |
927 | } | 950 | } |
928 | } | 951 | } |
@@ -1025,7 +1048,12 @@ impl ModCollector<'_, '_> { | |||
1025 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; | 1048 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; |
1026 | let def: ModuleDefId = module.into(); | 1049 | let def: ModuleDefId = module.into(); |
1027 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); | 1050 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
1028 | self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis, false))], vis); | 1051 | self.def_collector.update( |
1052 | self.module_id, | ||
1053 | &[(name, PerNs::from_def(def, vis, false))], | ||
1054 | vis, | ||
1055 | ImportType::Named, | ||
1056 | ); | ||
1029 | res | 1057 | res |
1030 | } | 1058 | } |
1031 | 1059 | ||
@@ -1154,6 +1182,7 @@ mod tests { | |||
1154 | mod_dirs: FxHashMap::default(), | 1182 | mod_dirs: FxHashMap::default(), |
1155 | cfg_options: &CfgOptions::default(), | 1183 | cfg_options: &CfgOptions::default(), |
1156 | proc_macros: Default::default(), | 1184 | proc_macros: Default::default(), |
1185 | from_glob_import: Default::default(), | ||
1157 | }; | 1186 | }; |
1158 | collector.collect(); | 1187 | collector.collect(); |
1159 | collector.def_map | 1188 | collector.def_map |
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index 2f440975a..7f3d7509c 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs | |||
@@ -276,3 +276,93 @@ fn glob_shadowed_def() { | |||
276 | "### | 276 | "### |
277 | ); | 277 | ); |
278 | } | 278 | } |
279 | |||
280 | #[test] | ||
281 | fn glob_shadowed_def_reversed() { | ||
282 | let map = def_map( | ||
283 | r###" | ||
284 | //- /lib.rs | ||
285 | mod foo; | ||
286 | mod bar; | ||
287 | |||
288 | use bar::baz; | ||
289 | use foo::*; | ||
290 | |||
291 | use baz::Bar; | ||
292 | |||
293 | //- /foo.rs | ||
294 | pub mod baz { | ||
295 | pub struct Foo; | ||
296 | } | ||
297 | |||
298 | //- /bar.rs | ||
299 | pub mod baz { | ||
300 | pub struct Bar; | ||
301 | } | ||
302 | "###, | ||
303 | ); | ||
304 | assert_snapshot!(map, @r###" | ||
305 | ⋮crate | ||
306 | ⋮Bar: t v | ||
307 | ⋮bar: t | ||
308 | ⋮baz: t | ||
309 | ⋮foo: t | ||
310 | ⋮ | ||
311 | ⋮crate::bar | ||
312 | ⋮baz: t | ||
313 | ⋮ | ||
314 | ⋮crate::bar::baz | ||
315 | ⋮Bar: t v | ||
316 | ⋮ | ||
317 | ⋮crate::foo | ||
318 | ⋮baz: t | ||
319 | ⋮ | ||
320 | ⋮crate::foo::baz | ||
321 | ⋮Foo: t v | ||
322 | "### | ||
323 | ); | ||
324 | } | ||
325 | |||
326 | #[test] | ||
327 | fn glob_shadowed_def_dependencies() { | ||
328 | let map = def_map( | ||
329 | r###" | ||
330 | //- /lib.rs | ||
331 | mod a { pub mod foo { pub struct X; } } | ||
332 | mod b { pub use super::a::foo; } | ||
333 | mod c { pub mod foo { pub struct Y; } } | ||
334 | mod d { | ||
335 | use super::c::foo; | ||
336 | use super::b::*; | ||
337 | use foo::Y; | ||
338 | } | ||
339 | "###, | ||
340 | ); | ||
341 | assert_snapshot!(map, @r###" | ||
342 | ⋮crate | ||
343 | ⋮a: t | ||
344 | ⋮b: t | ||
345 | ⋮c: t | ||
346 | ⋮d: t | ||
347 | ⋮ | ||
348 | ⋮crate::d | ||
349 | ⋮Y: t v | ||
350 | ⋮foo: t | ||
351 | ⋮ | ||
352 | ⋮crate::c | ||
353 | ⋮foo: t | ||
354 | ⋮ | ||
355 | ⋮crate::c::foo | ||
356 | ⋮Y: t v | ||
357 | ⋮ | ||
358 | ⋮crate::b | ||
359 | ⋮foo: t | ||
360 | ⋮ | ||
361 | ⋮crate::a | ||
362 | ⋮foo: t | ||
363 | ⋮ | ||
364 | ⋮crate::a::foo | ||
365 | ⋮X: t v | ||
366 | "### | ||
367 | ); | ||
368 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index d7ef9add6..7d8197f8b 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -1739,6 +1739,52 @@ fn main() { | |||
1739 | assert_eq!(t, "u32"); | 1739 | assert_eq!(t, "u32"); |
1740 | } | 1740 | } |
1741 | 1741 | ||
1742 | // This test is actually testing the shadowing behavior within ra_hir_def. It | ||
1743 | // lives here because the testing infrastructure in ra_hir_def isn't currently | ||
1744 | // capable of asserting the necessary conditions. | ||
1745 | #[test] | ||
1746 | fn should_be_shadowing_imports() { | ||
1747 | let t = type_at( | ||
1748 | r#" | ||
1749 | mod a { | ||
1750 | pub fn foo() -> i8 {0} | ||
1751 | pub struct foo { a: i8 } | ||
1752 | } | ||
1753 | mod b { pub fn foo () -> u8 {0} } | ||
1754 | mod c { pub struct foo { a: u8 } } | ||
1755 | mod d { | ||
1756 | pub use super::a::*; | ||
1757 | pub use super::c::foo; | ||
1758 | pub use super::b::foo; | ||
1759 | } | ||
1760 | |||
1761 | fn main() { | ||
1762 | d::foo()<|>; | ||
1763 | }"#, | ||
1764 | ); | ||
1765 | assert_eq!(t, "u8"); | ||
1766 | |||
1767 | let t = type_at( | ||
1768 | r#" | ||
1769 | mod a { | ||
1770 | pub fn foo() -> i8 {0} | ||
1771 | pub struct foo { a: i8 } | ||
1772 | } | ||
1773 | mod b { pub fn foo () -> u8 {0} } | ||
1774 | mod c { pub struct foo { a: u8 } } | ||
1775 | mod d { | ||
1776 | pub use super::a::*; | ||
1777 | pub use super::c::foo; | ||
1778 | pub use super::b::foo; | ||
1779 | } | ||
1780 | |||
1781 | fn main() { | ||
1782 | d::foo{a:0<|>}; | ||
1783 | }"#, | ||
1784 | ); | ||
1785 | assert_eq!(t, "u8"); | ||
1786 | } | ||
1787 | |||
1742 | #[test] | 1788 | #[test] |
1743 | fn closure_return() { | 1789 | fn closure_return() { |
1744 | assert_snapshot!( | 1790 | assert_snapshot!( |