diff options
author | Florian Diebold <[email protected]> | 2019-12-25 17:05:16 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-26 15:23:40 +0000 |
commit | 21359c3ab5fc497d11b2c0f0435c7635336a726e (patch) | |
tree | ad438e045f50be776a9245ceb367598e7b60f8f9 | |
parent | 8ac25f119eb45d425370d9f7f093bc206e6c4a9f (diff) |
Take visibility into account for glob imports
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 80 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/globs.rs | 78 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/incremental.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/per_ns.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/visibility.rs | 20 |
7 files changed, 165 insertions, 43 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index d77f37f67..db5f469c7 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -149,16 +149,8 @@ impl ItemScope { | |||
149 | changed | 149 | changed |
150 | } | 150 | } |
151 | 151 | ||
152 | #[cfg(test)] | 152 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { |
153 | pub(crate) fn collect_resolutions(&self) -> Vec<(Name, PerNs)> { | 153 | self.visible.iter().map(|(name, res)| (name.clone(), res.clone())) |
154 | self.visible.iter().map(|(name, res)| (name.clone(), res.clone())).collect() | ||
155 | } | ||
156 | |||
157 | pub(crate) fn collect_resolutions_with_vis( | ||
158 | &self, | ||
159 | vis: ResolvedVisibility, | ||
160 | ) -> Vec<(Name, PerNs)> { | ||
161 | self.visible.iter().map(|(name, res)| (name.clone(), res.with_visibility(vis))).collect() | ||
162 | } | 154 | } |
163 | 155 | ||
164 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | 156 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 5b8478037..51df44d2f 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -109,7 +109,7 @@ struct MacroDirective { | |||
109 | struct DefCollector<'a, DB> { | 109 | struct DefCollector<'a, DB> { |
110 | db: &'a DB, | 110 | db: &'a DB, |
111 | def_map: CrateDefMap, | 111 | def_map: CrateDefMap, |
112 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>, | 112 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, ResolvedVisibility)>>, |
113 | unresolved_imports: Vec<ImportDirective>, | 113 | unresolved_imports: Vec<ImportDirective>, |
114 | resolved_imports: Vec<ImportDirective>, | 114 | resolved_imports: Vec<ImportDirective>, |
115 | unexpanded_macros: Vec<MacroDirective>, | 115 | unexpanded_macros: Vec<MacroDirective>, |
@@ -218,6 +218,7 @@ where | |||
218 | self.update( | 218 | self.update( |
219 | self.def_map.root, | 219 | self.def_map.root, |
220 | &[(name, PerNs::macros(macro_, ResolvedVisibility::Public))], | 220 | &[(name, PerNs::macros(macro_, ResolvedVisibility::Public))], |
221 | ResolvedVisibility::Public, | ||
221 | ); | 222 | ); |
222 | } | 223 | } |
223 | } | 224 | } |
@@ -352,7 +353,6 @@ where | |||
352 | 353 | ||
353 | fn record_resolved_import(&mut self, directive: &ImportDirective) { | 354 | fn record_resolved_import(&mut self, directive: &ImportDirective) { |
354 | let module_id = directive.module_id; | 355 | let module_id = directive.module_id; |
355 | let import_id = directive.import_id; | ||
356 | let import = &directive.import; | 356 | let import = &directive.import; |
357 | let def = directive.status.namespaces(); | 357 | let def = directive.status.namespaces(); |
358 | let vis = self | 358 | let vis = self |
@@ -373,28 +373,48 @@ where | |||
373 | let item_map = self.db.crate_def_map(m.krate); | 373 | let item_map = self.db.crate_def_map(m.krate); |
374 | let scope = &item_map[m.local_id].scope; | 374 | let scope = &item_map[m.local_id].scope; |
375 | 375 | ||
376 | // TODO: only use names we can see | ||
377 | |||
378 | // Module scoped macros is included | 376 | // Module scoped macros is included |
379 | let items = scope.collect_resolutions_with_vis(vis); | 377 | let items = scope |
380 | 378 | .resolutions() | |
381 | self.update(module_id, &items); | 379 | // only keep visible names... |
380 | .map(|(n, res)| { | ||
381 | ( | ||
382 | n, | ||
383 | res.filter_visibility(|v| { | ||
384 | v.visible_from_def_map(&self.def_map, module_id) | ||
385 | }), | ||
386 | ) | ||
387 | }) | ||
388 | .filter(|(_, res)| !res.is_none()) | ||
389 | .collect::<Vec<_>>(); | ||
390 | |||
391 | self.update(module_id, &items, vis); | ||
382 | } else { | 392 | } else { |
383 | // glob import from same crate => we do an initial | 393 | // glob import from same crate => we do an initial |
384 | // import, and then need to propagate any further | 394 | // import, and then need to propagate any further |
385 | // additions | 395 | // additions |
386 | let scope = &self.def_map[m.local_id].scope; | 396 | let scope = &self.def_map[m.local_id].scope; |
387 | 397 | ||
388 | // TODO: only use names we can see | ||
389 | |||
390 | // Module scoped macros is included | 398 | // Module scoped macros is included |
391 | let items = scope.collect_resolutions_with_vis(vis); | 399 | let items = scope |
392 | 400 | .resolutions() | |
393 | self.update(module_id, &items); | 401 | // only keep visible names... |
402 | .map(|(n, res)| { | ||
403 | ( | ||
404 | n, | ||
405 | res.filter_visibility(|v| { | ||
406 | v.visible_from_def_map(&self.def_map, module_id) | ||
407 | }), | ||
408 | ) | ||
409 | }) | ||
410 | .filter(|(_, res)| !res.is_none()) | ||
411 | .collect::<Vec<_>>(); | ||
412 | |||
413 | self.update(module_id, &items, vis); | ||
394 | // record the glob import in case we add further items | 414 | // record the glob import in case we add further items |
395 | let glob = self.glob_imports.entry(m.local_id).or_default(); | 415 | let glob = self.glob_imports.entry(m.local_id).or_default(); |
396 | if !glob.iter().any(|it| *it == (module_id, import_id)) { | 416 | if !glob.iter().any(|(mid, _)| *mid == module_id) { |
397 | glob.push((module_id, import_id)); | 417 | glob.push((module_id, vis)); |
398 | } | 418 | } |
399 | } | 419 | } |
400 | } | 420 | } |
@@ -412,7 +432,7 @@ where | |||
412 | (name, res) | 432 | (name, res) |
413 | }) | 433 | }) |
414 | .collect::<Vec<_>>(); | 434 | .collect::<Vec<_>>(); |
415 | self.update(module_id, &resolutions); | 435 | self.update(module_id, &resolutions, vis); |
416 | } | 436 | } |
417 | Some(d) => { | 437 | Some(d) => { |
418 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | 438 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); |
@@ -434,21 +454,29 @@ where | |||
434 | } | 454 | } |
435 | } | 455 | } |
436 | 456 | ||
437 | self.update(module_id, &[(name, def.with_visibility(vis))]); | 457 | self.update(module_id, &[(name, def)], vis); |
438 | } | 458 | } |
439 | None => tested_by!(bogus_paths), | 459 | None => tested_by!(bogus_paths), |
440 | } | 460 | } |
441 | } | 461 | } |
442 | } | 462 | } |
443 | 463 | ||
444 | fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) { | 464 | fn update( |
445 | self.update_recursive(module_id, resolutions, 0) | 465 | &mut self, |
466 | module_id: LocalModuleId, | ||
467 | resolutions: &[(Name, PerNs)], | ||
468 | vis: ResolvedVisibility, | ||
469 | ) { | ||
470 | self.update_recursive(module_id, resolutions, vis, 0) | ||
446 | } | 471 | } |
447 | 472 | ||
448 | fn update_recursive( | 473 | fn update_recursive( |
449 | &mut self, | 474 | &mut self, |
450 | module_id: LocalModuleId, | 475 | module_id: LocalModuleId, |
451 | resolutions: &[(Name, PerNs)], | 476 | resolutions: &[(Name, PerNs)], |
477 | // All resolutions are imported with this visibility; the visibilies in | ||
478 | // the `PerNs` values are ignored and overwritten | ||
479 | vis: ResolvedVisibility, | ||
452 | depth: usize, | 480 | depth: usize, |
453 | ) { | 481 | ) { |
454 | if depth > 100 { | 482 | if depth > 100 { |
@@ -458,7 +486,7 @@ where | |||
458 | let scope = &mut self.def_map.modules[module_id].scope; | 486 | let scope = &mut self.def_map.modules[module_id].scope; |
459 | let mut changed = false; | 487 | let mut changed = false; |
460 | for (name, res) in resolutions { | 488 | for (name, res) in resolutions { |
461 | changed |= scope.push_res(name.clone(), *res); | 489 | changed |= scope.push_res(name.clone(), res.with_visibility(vis)); |
462 | } | 490 | } |
463 | 491 | ||
464 | if !changed { | 492 | if !changed { |
@@ -471,9 +499,13 @@ where | |||
471 | .flat_map(|v| v.iter()) | 499 | .flat_map(|v| v.iter()) |
472 | .cloned() | 500 | .cloned() |
473 | .collect::<Vec<_>>(); | 501 | .collect::<Vec<_>>(); |
474 | for (glob_importing_module, _glob_import) in glob_imports { | 502 | for (glob_importing_module, glob_import_vis) in glob_imports { |
475 | // We pass the glob import so that the tracked import in those modules is that glob import | 503 | // we know all resolutions have the same visibility (`vis`), so we |
476 | self.update_recursive(glob_importing_module, resolutions, depth + 1); | 504 | // just need to check that once |
505 | if !vis.visible_from_def_map(&self.def_map, glob_importing_module) { | ||
506 | continue; | ||
507 | } | ||
508 | self.update_recursive(glob_importing_module, resolutions, glob_import_vis, depth + 1); | ||
477 | } | 509 | } |
478 | } | 510 | } |
479 | 511 | ||
@@ -715,7 +747,7 @@ where | |||
715 | let def: ModuleDefId = module.into(); | 747 | let def: ModuleDefId = module.into(); |
716 | let vis = ResolvedVisibility::Public; // TODO handle module visibility | 748 | let vis = ResolvedVisibility::Public; // TODO handle module visibility |
717 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); | 749 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
718 | self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))]); | 750 | self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))], vis); |
719 | res | 751 | res |
720 | } | 752 | } |
721 | 753 | ||
@@ -780,7 +812,7 @@ where | |||
780 | .def_map | 812 | .def_map |
781 | .resolve_visibility(self.def_collector.db, self.module_id, vis) | 813 | .resolve_visibility(self.def_collector.db, self.module_id, vis) |
782 | .unwrap_or(ResolvedVisibility::Public); | 814 | .unwrap_or(ResolvedVisibility::Public); |
783 | self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))]) | 815 | self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis))], vis) |
784 | } | 816 | } |
785 | 817 | ||
786 | fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { | 818 | fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { |
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index ff474b53b..78bcdc850 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -12,8 +12,8 @@ use test_utils::covers; | |||
12 | 12 | ||
13 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId}; | 13 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId}; |
14 | 14 | ||
15 | fn def_map(fixtute: &str) -> String { | 15 | fn def_map(fixture: &str) -> String { |
16 | let dm = compute_crate_def_map(fixtute); | 16 | let dm = compute_crate_def_map(fixture); |
17 | render_crate_def_map(&dm) | 17 | render_crate_def_map(&dm) |
18 | } | 18 | } |
19 | 19 | ||
@@ -32,7 +32,7 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { | |||
32 | *buf += path; | 32 | *buf += path; |
33 | *buf += "\n"; | 33 | *buf += "\n"; |
34 | 34 | ||
35 | let mut entries = map.modules[module].scope.collect_resolutions(); | 35 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); |
36 | entries.sort_by_key(|(name, _)| name.clone()); | 36 | entries.sort_by_key(|(name, _)| name.clone()); |
37 | 37 | ||
38 | for (name, def) in entries { | 38 | for (name, def) in entries { |
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index 5e24cb94d..5f137d3a6 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs | |||
@@ -74,6 +74,84 @@ fn glob_2() { | |||
74 | } | 74 | } |
75 | 75 | ||
76 | #[test] | 76 | #[test] |
77 | fn glob_privacy_1() { | ||
78 | let map = def_map( | ||
79 | " | ||
80 | //- /lib.rs | ||
81 | mod foo; | ||
82 | use foo::*; | ||
83 | |||
84 | //- /foo/mod.rs | ||
85 | pub mod bar; | ||
86 | pub use self::bar::*; | ||
87 | struct PrivateStructFoo; | ||
88 | |||
89 | //- /foo/bar.rs | ||
90 | pub struct Baz; | ||
91 | struct PrivateStructBar; | ||
92 | pub use super::*; | ||
93 | ", | ||
94 | ); | ||
95 | assert_snapshot!(map, @r###" | ||
96 | crate | ||
97 | Baz: t v | ||
98 | bar: t | ||
99 | foo: t | ||
100 | |||
101 | crate::foo | ||
102 | Baz: t v | ||
103 | PrivateStructFoo: t v | ||
104 | bar: t | ||
105 | |||
106 | crate::foo::bar | ||
107 | Baz: t v | ||
108 | PrivateStructBar: t v | ||
109 | PrivateStructFoo: t v | ||
110 | bar: t | ||
111 | "### | ||
112 | ); | ||
113 | } | ||
114 | |||
115 | #[test] | ||
116 | fn glob_privacy_2() { | ||
117 | let map = def_map( | ||
118 | " | ||
119 | //- /lib.rs | ||
120 | mod foo; | ||
121 | use foo::*; | ||
122 | use foo::bar::*; | ||
123 | |||
124 | //- /foo/mod.rs | ||
125 | pub mod bar; | ||
126 | fn Foo() {}; | ||
127 | pub struct Foo {}; | ||
128 | |||
129 | //- /foo/bar.rs | ||
130 | pub(super) struct PrivateBaz; | ||
131 | struct PrivateBar; | ||
132 | pub(crate) struct PubCrateStruct; | ||
133 | ", | ||
134 | ); | ||
135 | assert_snapshot!(map, @r###" | ||
136 | crate | ||
137 | Foo: t | ||
138 | PubCrateStruct: t v | ||
139 | bar: t | ||
140 | foo: t | ||
141 | |||
142 | crate::foo | ||
143 | Foo: t v | ||
144 | bar: t | ||
145 | |||
146 | crate::foo::bar | ||
147 | PrivateBar: t v | ||
148 | PrivateBaz: t v | ||
149 | PubCrateStruct: t v | ||
150 | "### | ||
151 | ); | ||
152 | } | ||
153 | |||
154 | #[test] | ||
77 | fn glob_across_crates() { | 155 | fn glob_across_crates() { |
78 | covers!(glob_across_crates); | 156 | covers!(glob_across_crates); |
79 | let map = def_map( | 157 | let map = def_map( |
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index ef2e9435c..faeb7aa4d 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
116 | let events = db.log_executed(|| { | 116 | let events = db.log_executed(|| { |
117 | let crate_def_map = db.crate_def_map(krate); | 117 | let crate_def_map = db.crate_def_map(krate); |
118 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | 118 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); |
119 | assert_eq!(module_data.scope.collect_resolutions().len(), 1); | 119 | assert_eq!(module_data.scope.resolutions().collect::<Vec<_>>().len(), 1); |
120 | }); | 120 | }); |
121 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 121 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
122 | } | 122 | } |
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
126 | let events = db.log_executed(|| { | 126 | let events = db.log_executed(|| { |
127 | let crate_def_map = db.crate_def_map(krate); | 127 | let crate_def_map = db.crate_def_map(krate); |
128 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | 128 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); |
129 | assert_eq!(module_data.scope.collect_resolutions().len(), 1); | 129 | assert_eq!(module_data.scope.resolutions().collect::<Vec<_>>().len(), 1); |
130 | }); | 130 | }); |
131 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 131 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
132 | } | 132 | } |
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs index 16e61a6a5..7637d8a37 100644 --- a/crates/ra_hir_def/src/per_ns.rs +++ b/crates/ra_hir_def/src/per_ns.rs | |||
@@ -61,6 +61,14 @@ impl PerNs { | |||
61 | self.macros.map(|it| it.0) | 61 | self.macros.map(|it| it.0) |
62 | } | 62 | } |
63 | 63 | ||
64 | pub fn filter_visibility(self, mut f: impl FnMut(ResolvedVisibility) -> bool) -> PerNs { | ||
65 | PerNs { | ||
66 | types: self.types.filter(|(_, v)| f(*v)), | ||
67 | values: self.values.filter(|(_, v)| f(*v)), | ||
68 | macros: self.macros.filter(|(_, v)| f(*v)), | ||
69 | } | ||
70 | } | ||
71 | |||
64 | pub fn with_visibility(self, vis: ResolvedVisibility) -> PerNs { | 72 | pub fn with_visibility(self, vis: ResolvedVisibility) -> PerNs { |
65 | PerNs { | 73 | PerNs { |
66 | types: self.types.map(|(it, _)| (it, vis)), | 74 | types: self.types.map(|(it, _)| (it, vis)), |
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index 8cac52630..990b2975c 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs | |||
@@ -134,13 +134,25 @@ impl ResolvedVisibility { | |||
134 | if from_module.krate != to_module.krate { | 134 | if from_module.krate != to_module.krate { |
135 | return false; | 135 | return false; |
136 | } | 136 | } |
137 | // from_module needs to be a descendant of to_module | ||
138 | let def_map = db.crate_def_map(from_module.krate); | 137 | let def_map = db.crate_def_map(from_module.krate); |
138 | self.visible_from_def_map(&def_map, from_module.local_id) | ||
139 | } | ||
140 | |||
141 | pub(crate) fn visible_from_def_map( | ||
142 | self, | ||
143 | def_map: &crate::nameres::CrateDefMap, | ||
144 | from_module: crate::LocalModuleId, | ||
145 | ) -> bool { | ||
146 | let to_module = match self { | ||
147 | ResolvedVisibility::Module(m) => m, | ||
148 | ResolvedVisibility::Public => return true, | ||
149 | }; | ||
150 | // from_module needs to be a descendant of to_module | ||
139 | let mut ancestors = std::iter::successors(Some(from_module), |m| { | 151 | let mut ancestors = std::iter::successors(Some(from_module), |m| { |
140 | let parent_id = def_map[m.local_id].parent?; | 152 | let parent_id = def_map[*m].parent?; |
141 | Some(ModuleId { local_id: parent_id, ..*m }) | 153 | Some(parent_id) |
142 | }); | 154 | }); |
143 | ancestors.any(|m| m == to_module) | 155 | ancestors.any(|m| m == to_module.local_id) |
144 | } | 156 | } |
145 | } | 157 | } |
146 | 158 | ||