diff options
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 72 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests.rs | 130 | ||||
-rw-r--r-- | crates/ra_hir_def/src/visibility.rs | 41 |
5 files changed, 248 insertions, 26 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index beeb98559..8fee4b15e 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -36,6 +36,8 @@ pub struct ItemScope { | |||
36 | 36 | ||
37 | defs: Vec<ModuleDefId>, | 37 | defs: Vec<ModuleDefId>, |
38 | impls: Vec<ImplId>, | 38 | impls: Vec<ImplId>, |
39 | /// Traits imported via `use Trait as _;`. | ||
40 | unnamed_trait_imports: FxHashMap<TraitId, Visibility>, | ||
39 | /// Macros visible in current module in legacy textual scope | 41 | /// Macros visible in current module in legacy textual scope |
40 | /// | 42 | /// |
41 | /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. | 43 | /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. |
@@ -126,10 +128,13 @@ impl ItemScope { | |||
126 | } | 128 | } |
127 | 129 | ||
128 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | 130 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { |
129 | self.types.values().filter_map(|(def, _)| match def { | 131 | self.types |
130 | ModuleDefId::TraitId(t) => Some(*t), | 132 | .values() |
131 | _ => None, | 133 | .filter_map(|(def, _)| match def { |
132 | }) | 134 | ModuleDefId::TraitId(t) => Some(*t), |
135 | _ => None, | ||
136 | }) | ||
137 | .chain(self.unnamed_trait_imports.keys().copied()) | ||
133 | } | 138 | } |
134 | 139 | ||
135 | pub(crate) fn define_def(&mut self, def: ModuleDefId) { | 140 | pub(crate) fn define_def(&mut self, def: ModuleDefId) { |
@@ -148,6 +153,14 @@ impl ItemScope { | |||
148 | self.legacy_macros.insert(name, mac); | 153 | self.legacy_macros.insert(name, mac); |
149 | } | 154 | } |
150 | 155 | ||
156 | pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { | ||
157 | self.unnamed_trait_imports.get(&tr).copied() | ||
158 | } | ||
159 | |||
160 | pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) { | ||
161 | self.unnamed_trait_imports.insert(tr, vis); | ||
162 | } | ||
163 | |||
151 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { | 164 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { |
152 | let mut changed = false; | 165 | let mut changed = false; |
153 | 166 | ||
@@ -241,8 +254,12 @@ impl ItemScope { | |||
241 | changed | 254 | changed |
242 | } | 255 | } |
243 | 256 | ||
244 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { | 257 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a { |
245 | self.entries().map(|(name, res)| (name.clone(), res)) | 258 | self.entries().map(|(name, res)| (Some(name.clone()), res)).chain( |
259 | self.unnamed_trait_imports | ||
260 | .iter() | ||
261 | .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))), | ||
262 | ) | ||
246 | } | 263 | } |
247 | 264 | ||
248 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | 265 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { |
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 5a9de3d3e..3d9b55a73 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -239,7 +239,7 @@ impl CrateDefMap { | |||
239 | entries.sort_by_key(|(name, _)| name.clone()); | 239 | entries.sort_by_key(|(name, _)| name.clone()); |
240 | 240 | ||
241 | for (name, def) in entries { | 241 | for (name, def) in entries { |
242 | format_to!(buf, "{}:", name); | 242 | format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string())); |
243 | 243 | ||
244 | if def.types.is_some() { | 244 | if def.types.is_some() { |
245 | buf.push_str(" t"); | 245 | buf.push_str(" t"); |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index d85a86c0a..a030cab47 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -310,7 +310,7 @@ impl DefCollector<'_> { | |||
310 | if export { | 310 | if export { |
311 | self.update( | 311 | self.update( |
312 | self.def_map.root, | 312 | self.def_map.root, |
313 | &[(name, PerNs::macros(macro_, Visibility::Public))], | 313 | &[(Some(name), PerNs::macros(macro_, Visibility::Public))], |
314 | Visibility::Public, | 314 | Visibility::Public, |
315 | ImportType::Named, | 315 | ImportType::Named, |
316 | ); | 316 | ); |
@@ -336,7 +336,7 @@ impl DefCollector<'_> { | |||
336 | fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { | 336 | fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { |
337 | self.update( | 337 | self.update( |
338 | self.def_map.root, | 338 | self.def_map.root, |
339 | &[(name, PerNs::macros(macro_, Visibility::Public))], | 339 | &[(Some(name), PerNs::macros(macro_, Visibility::Public))], |
340 | Visibility::Public, | 340 | Visibility::Public, |
341 | ImportType::Named, | 341 | ImportType::Named, |
342 | ); | 342 | ); |
@@ -534,7 +534,7 @@ impl DefCollector<'_> { | |||
534 | let name = variant_data.name.clone(); | 534 | let name = variant_data.name.clone(); |
535 | let variant = EnumVariantId { parent: e, local_id }; | 535 | let variant = EnumVariantId { parent: e, local_id }; |
536 | let res = PerNs::both(variant.into(), variant.into(), vis); | 536 | let res = PerNs::both(variant.into(), variant.into(), vis); |
537 | (name, res) | 537 | (Some(name), res) |
538 | }) | 538 | }) |
539 | .collect::<Vec<_>>(); | 539 | .collect::<Vec<_>>(); |
540 | self.update(module_id, &resolutions, vis, ImportType::Glob); | 540 | self.update(module_id, &resolutions, vis, ImportType::Glob); |
@@ -550,15 +550,15 @@ impl DefCollector<'_> { | |||
550 | match import.path.segments.last() { | 550 | match import.path.segments.last() { |
551 | Some(last_segment) => { | 551 | Some(last_segment) => { |
552 | let name = match &import.alias { | 552 | let name = match &import.alias { |
553 | Some(ImportAlias::Alias(name)) => name.clone(), | 553 | Some(ImportAlias::Alias(name)) => Some(name.clone()), |
554 | Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 | 554 | Some(ImportAlias::Underscore) => None, |
555 | None => last_segment.clone(), | 555 | None => Some(last_segment.clone()), |
556 | }; | 556 | }; |
557 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | 557 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); |
558 | 558 | ||
559 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 559 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
560 | if import.is_extern_crate && module_id == self.def_map.root { | 560 | if import.is_extern_crate && module_id == self.def_map.root { |
561 | if let Some(def) = def.take_types() { | 561 | if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) { |
562 | self.def_map.extern_prelude.insert(name.clone(), def); | 562 | self.def_map.extern_prelude.insert(name.clone(), def); |
563 | } | 563 | } |
564 | } | 564 | } |
@@ -573,7 +573,7 @@ impl DefCollector<'_> { | |||
573 | fn update( | 573 | fn update( |
574 | &mut self, | 574 | &mut self, |
575 | module_id: LocalModuleId, | 575 | module_id: LocalModuleId, |
576 | resolutions: &[(Name, PerNs)], | 576 | resolutions: &[(Option<Name>, PerNs)], |
577 | vis: Visibility, | 577 | vis: Visibility, |
578 | import_type: ImportType, | 578 | import_type: ImportType, |
579 | ) { | 579 | ) { |
@@ -584,7 +584,7 @@ impl DefCollector<'_> { | |||
584 | fn update_recursive( | 584 | fn update_recursive( |
585 | &mut self, | 585 | &mut self, |
586 | module_id: LocalModuleId, | 586 | module_id: LocalModuleId, |
587 | resolutions: &[(Name, PerNs)], | 587 | resolutions: &[(Option<Name>, PerNs)], |
588 | // All resolutions are imported with this visibility; the visibilies in | 588 | // All resolutions are imported with this visibility; the visibilies in |
589 | // the `PerNs` values are ignored and overwritten | 589 | // the `PerNs` values are ignored and overwritten |
590 | vis: Visibility, | 590 | vis: Visibility, |
@@ -595,15 +595,51 @@ impl DefCollector<'_> { | |||
595 | // prevent stack overflows (but this shouldn't be possible) | 595 | // prevent stack overflows (but this shouldn't be possible) |
596 | panic!("infinite recursion in glob imports!"); | 596 | panic!("infinite recursion in glob imports!"); |
597 | } | 597 | } |
598 | let scope = &mut self.def_map.modules[module_id].scope; | ||
599 | let mut changed = false; | 598 | let mut changed = false; |
599 | |||
600 | for (name, res) in resolutions { | 600 | for (name, res) in resolutions { |
601 | changed |= scope.push_res_with_import( | 601 | match name { |
602 | &mut self.from_glob_import, | 602 | Some(name) => { |
603 | (module_id, name.clone()), | 603 | let scope = &mut self.def_map.modules[module_id].scope; |
604 | res.with_visibility(vis), | 604 | changed |= scope.push_res_with_import( |
605 | import_type, | 605 | &mut self.from_glob_import, |
606 | ); | 606 | (module_id, name.clone()), |
607 | res.with_visibility(vis), | ||
608 | import_type, | ||
609 | ); | ||
610 | } | ||
611 | None => { | ||
612 | let tr = match res.take_types() { | ||
613 | Some(ModuleDefId::TraitId(tr)) => tr, | ||
614 | Some(other) => { | ||
615 | log::debug!("non-trait `_` import of {:?}", other); | ||
616 | continue; | ||
617 | } | ||
618 | None => continue, | ||
619 | }; | ||
620 | let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr); | ||
621 | let should_update = match old_vis { | ||
622 | None => true, | ||
623 | Some(old_vis) => { | ||
624 | let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| { | ||
625 | panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr); | ||
626 | }); | ||
627 | |||
628 | if max_vis == old_vis { | ||
629 | false | ||
630 | } else { | ||
631 | mark::hit!(upgrade_underscore_visibility); | ||
632 | true | ||
633 | } | ||
634 | } | ||
635 | }; | ||
636 | |||
637 | if should_update { | ||
638 | changed = true; | ||
639 | self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis); | ||
640 | } | ||
641 | } | ||
642 | } | ||
607 | } | 643 | } |
608 | 644 | ||
609 | if !changed { | 645 | if !changed { |
@@ -950,7 +986,7 @@ impl ModCollector<'_, '_> { | |||
950 | .unwrap_or(Visibility::Public); | 986 | .unwrap_or(Visibility::Public); |
951 | self.def_collector.update( | 987 | self.def_collector.update( |
952 | self.module_id, | 988 | self.module_id, |
953 | &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], | 989 | &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))], |
954 | vis, | 990 | vis, |
955 | ImportType::Named, | 991 | ImportType::Named, |
956 | ) | 992 | ) |
@@ -1057,7 +1093,7 @@ impl ModCollector<'_, '_> { | |||
1057 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); | 1093 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
1058 | self.def_collector.update( | 1094 | self.def_collector.update( |
1059 | self.module_id, | 1095 | self.module_id, |
1060 | &[(name, PerNs::from_def(def, vis, false))], | 1096 | &[(Some(name), PerNs::from_def(def, vis, false))], |
1061 | vis, | 1097 | vis, |
1062 | ImportType::Named, | 1098 | ImportType::Named, |
1063 | ); | 1099 | ); |
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 205d3528b..839b1de57 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -558,3 +558,133 @@ mod b { | |||
558 | "#]], | 558 | "#]], |
559 | ); | 559 | ); |
560 | } | 560 | } |
561 | |||
562 | #[test] | ||
563 | fn underscore_import() { | ||
564 | check( | ||
565 | r#" | ||
566 | //- /main.rs | ||
567 | use tr::Tr as _; | ||
568 | use tr::Tr2 as _; | ||
569 | |||
570 | mod tr { | ||
571 | pub trait Tr {} | ||
572 | pub trait Tr2 {} | ||
573 | } | ||
574 | "#, | ||
575 | expect![[r#" | ||
576 | crate | ||
577 | _: t | ||
578 | _: t | ||
579 | tr: t | ||
580 | |||
581 | crate::tr | ||
582 | Tr: t | ||
583 | Tr2: t | ||
584 | "#]], | ||
585 | ); | ||
586 | } | ||
587 | |||
588 | #[test] | ||
589 | fn underscore_reexport() { | ||
590 | check( | ||
591 | r#" | ||
592 | //- /main.rs | ||
593 | mod tr { | ||
594 | pub trait PubTr {} | ||
595 | pub trait PrivTr {} | ||
596 | } | ||
597 | mod reex { | ||
598 | use crate::tr::PrivTr as _; | ||
599 | pub use crate::tr::PubTr as _; | ||
600 | } | ||
601 | use crate::reex::*; | ||
602 | "#, | ||
603 | expect![[r#" | ||
604 | crate | ||
605 | _: t | ||
606 | reex: t | ||
607 | tr: t | ||
608 | |||
609 | crate::tr | ||
610 | PrivTr: t | ||
611 | PubTr: t | ||
612 | |||
613 | crate::reex | ||
614 | _: t | ||
615 | _: t | ||
616 | "#]], | ||
617 | ); | ||
618 | } | ||
619 | |||
620 | #[test] | ||
621 | fn underscore_pub_crate_reexport() { | ||
622 | mark::check!(upgrade_underscore_visibility); | ||
623 | check( | ||
624 | r#" | ||
625 | //- /main.rs crate:main deps:lib | ||
626 | use lib::*; | ||
627 | |||
628 | //- /lib.rs crate:lib | ||
629 | use tr::Tr as _; | ||
630 | pub use tr::Tr as _; | ||
631 | |||
632 | mod tr { | ||
633 | pub trait Tr {} | ||
634 | } | ||
635 | "#, | ||
636 | expect![[r#" | ||
637 | crate | ||
638 | _: t | ||
639 | "#]], | ||
640 | ); | ||
641 | } | ||
642 | |||
643 | #[test] | ||
644 | fn underscore_nontrait() { | ||
645 | check( | ||
646 | r#" | ||
647 | //- /main.rs | ||
648 | mod m { | ||
649 | pub struct Struct; | ||
650 | pub enum Enum {} | ||
651 | pub const CONST: () = (); | ||
652 | } | ||
653 | use crate::m::{Struct as _, Enum as _, CONST as _}; | ||
654 | "#, | ||
655 | expect![[r#" | ||
656 | crate | ||
657 | m: t | ||
658 | |||
659 | crate::m | ||
660 | CONST: v | ||
661 | Enum: t | ||
662 | Struct: t v | ||
663 | "#]], | ||
664 | ); | ||
665 | } | ||
666 | |||
667 | #[test] | ||
668 | fn underscore_name_conflict() { | ||
669 | check( | ||
670 | r#" | ||
671 | //- /main.rs | ||
672 | struct Tr; | ||
673 | |||
674 | use tr::Tr as _; | ||
675 | |||
676 | mod tr { | ||
677 | pub trait Tr {} | ||
678 | } | ||
679 | "#, | ||
680 | expect![[r#" | ||
681 | crate | ||
682 | _: t | ||
683 | Tr: t v | ||
684 | tr: t | ||
685 | |||
686 | crate::tr | ||
687 | Tr: t | ||
688 | "#]], | ||
689 | ); | ||
690 | } | ||
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index 8136cb50c..1abffb4c3 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs | |||
@@ -5,6 +5,7 @@ use ra_syntax::ast; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | nameres::CrateDefMap, | ||
8 | path::{ModPath, PathKind}, | 9 | path::{ModPath, PathKind}, |
9 | ModuleId, | 10 | ModuleId, |
10 | }; | 11 | }; |
@@ -115,7 +116,7 @@ impl Visibility { | |||
115 | 116 | ||
116 | pub(crate) fn is_visible_from_def_map( | 117 | pub(crate) fn is_visible_from_def_map( |
117 | self, | 118 | self, |
118 | def_map: &crate::nameres::CrateDefMap, | 119 | def_map: &CrateDefMap, |
119 | from_module: crate::LocalModuleId, | 120 | from_module: crate::LocalModuleId, |
120 | ) -> bool { | 121 | ) -> bool { |
121 | let to_module = match self { | 122 | let to_module = match self { |
@@ -129,4 +130,42 @@ impl Visibility { | |||
129 | }); | 130 | }); |
130 | ancestors.any(|m| m == to_module.local_id) | 131 | ancestors.any(|m| m == to_module.local_id) |
131 | } | 132 | } |
133 | |||
134 | /// Returns the most permissive visibility of `self` and `other`. | ||
135 | /// | ||
136 | /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only | ||
137 | /// visible in unrelated modules). | ||
138 | pub(crate) fn max(self, other: Visibility, def_map: &CrateDefMap) -> Option<Visibility> { | ||
139 | match (self, other) { | ||
140 | (Visibility::Module(_), Visibility::Public) | ||
141 | | (Visibility::Public, Visibility::Module(_)) | ||
142 | | (Visibility::Public, Visibility::Public) => Some(Visibility::Public), | ||
143 | (Visibility::Module(mod_a), Visibility::Module(mod_b)) => { | ||
144 | if mod_a.krate != mod_b.krate { | ||
145 | return None; | ||
146 | } | ||
147 | |||
148 | let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| { | ||
149 | let parent_id = def_map[*m].parent?; | ||
150 | Some(parent_id) | ||
151 | }); | ||
152 | let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| { | ||
153 | let parent_id = def_map[*m].parent?; | ||
154 | Some(parent_id) | ||
155 | }); | ||
156 | |||
157 | if a_ancestors.any(|m| m == mod_b.local_id) { | ||
158 | // B is above A | ||
159 | return Some(Visibility::Module(mod_b)); | ||
160 | } | ||
161 | |||
162 | if b_ancestors.any(|m| m == mod_a.local_id) { | ||
163 | // A is above B | ||
164 | return Some(Visibility::Module(mod_a)); | ||
165 | } | ||
166 | |||
167 | None | ||
168 | } | ||
169 | } | ||
170 | } | ||
132 | } | 171 | } |