aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/item_scope.rs79
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs49
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs90
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs46
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 @@
4use hir_expand::name::Name; 4use hir_expand::name::Name;
5use once_cell::sync::Lazy; 5use once_cell::sync::Lazy;
6use ra_db::CrateId; 6use ra_db::CrateId;
7use rustc_hash::FxHashMap; 7use rustc_hash::{FxHashMap, FxHashSet};
8use test_utils::mark; 8use test_utils::mark;
9 9
10use crate::{ 10use 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)]
16pub(crate) enum ImportType {
17 Glob,
18 Named,
19}
20
21#[derive(Debug, Default)]
22pub 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)]
16pub struct ItemScope { 29pub 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;
20use crate::{ 20use 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
191impl DefCollector<'_> { 194impl 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]
281fn 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]
327fn 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]
1746fn should_be_shadowing_imports() {
1747 let t = type_at(
1748 r#"
1749mod a {
1750 pub fn foo() -> i8 {0}
1751 pub struct foo { a: i8 }
1752}
1753mod b { pub fn foo () -> u8 {0} }
1754mod c { pub struct foo { a: u8 } }
1755mod d {
1756 pub use super::a::*;
1757 pub use super::c::foo;
1758 pub use super::b::foo;
1759}
1760
1761fn main() {
1762 d::foo()<|>;
1763}"#,
1764 );
1765 assert_eq!(t, "u8");
1766
1767 let t = type_at(
1768 r#"
1769mod a {
1770 pub fn foo() -> i8 {0}
1771 pub struct foo { a: i8 }
1772}
1773mod b { pub fn foo () -> u8 {0} }
1774mod c { pub struct foo { a: u8 } }
1775mod d {
1776 pub use super::a::*;
1777 pub use super::c::foo;
1778 pub use super::b::foo;
1779}
1780
1781fn main() {
1782 d::foo{a:0<|>};
1783}"#,
1784 );
1785 assert_eq!(t, "u8");
1786}
1787
1742#[test] 1788#[test]
1743fn closure_return() { 1789fn closure_return() {
1744 assert_snapshot!( 1790 assert_snapshot!(