aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/item_scope.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/item_scope.rs')
-rw-r--r--crates/ra_hir_def/src/item_scope.rs174
1 files changed, 146 insertions, 28 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index fc15948ad..beeb98559 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -1,18 +1,39 @@
1//! Describes items defined or visible (ie, imported) in a certain scope. 1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks. 2//! This is shared between modules and blocks.
3 3
4use std::collections::hash_map::Entry;
5
4use hir_expand::name::Name; 6use hir_expand::name::Name;
5use once_cell::sync::Lazy; 7use once_cell::sync::Lazy;
6use rustc_hash::FxHashMap; 8use ra_db::CrateId;
9use rustc_hash::{FxHashMap, FxHashSet};
10use test_utils::mark;
7 11
8use crate::{ 12use crate::{
9 per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, 13 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
10 TraitId, 14 LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId,
11}; 15};
12 16
17#[derive(Copy, Clone)]
18pub(crate) enum ImportType {
19 Glob,
20 Named,
21}
22
23#[derive(Debug, Default)]
24pub struct PerNsGlobImports {
25 types: FxHashSet<(LocalModuleId, Name)>,
26 values: FxHashSet<(LocalModuleId, Name)>,
27 macros: FxHashSet<(LocalModuleId, Name)>,
28}
29
13#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
14pub struct ItemScope { 31pub struct ItemScope {
15 visible: FxHashMap<Name, PerNs>, 32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
36
16 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
17 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
18 /// Macros visible in current module in legacy textual scope 39 /// Macros visible in current module in legacy textual scope
@@ -50,14 +71,16 @@ pub(crate) enum BuiltinShadowMode {
50/// Other methods will only resolve values, types and module scoped macros only. 71/// Other methods will only resolve values, types and module scoped macros only.
51impl ItemScope { 72impl ItemScope {
52 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 73 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
53 //FIXME: shadowing 74 // FIXME: shadowing
54 self.visible.iter().map(|(n, def)| (n, *def)) 75 let keys: FxHashSet<_> = self
55 } 76 .types
77 .keys()
78 .chain(self.values.keys())
79 .chain(self.macros.keys())
80 .chain(self.unresolved.iter())
81 .collect();
56 82
57 pub fn entries_without_primitives<'a>( 83 keys.into_iter().map(move |name| (name, self.get(name)))
58 &'a self,
59 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
60 self.visible.iter().map(|(n, def)| (n, *def))
61 } 84 }
62 85
63 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { 86 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
@@ -76,7 +99,7 @@ impl ItemScope {
76 99
77 /// Iterate over all module scoped macros 100 /// Iterate over all module scoped macros
78 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 101 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
79 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 102 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
80 } 103 }
81 104
82 /// Iterate over all legacy textual scoped macros visible at the end of the module 105 /// Iterate over all legacy textual scoped macros visible at the end of the module
@@ -86,12 +109,16 @@ impl ItemScope {
86 109
87 /// Get a name from current module scope, legacy macros are not included 110 /// Get a name from current module scope, legacy macros are not included
88 pub(crate) fn get(&self, name: &Name) -> PerNs { 111 pub(crate) fn get(&self, name: &Name) -> PerNs {
89 self.visible.get(name).copied().unwrap_or_else(PerNs::none) 112 PerNs {
113 types: self.types.get(name).copied(),
114 values: self.values.get(name).copied(),
115 macros: self.macros.get(name).copied(),
116 }
90 } 117 }
91 118
92 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 119 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
93 for (name, per_ns) in &self.visible { 120 for (name, per_ns) in self.entries() {
94 if let Some(vis) = item.match_with(*per_ns) { 121 if let Some(vis) = item.match_with(per_ns) {
95 return Some((name, vis)); 122 return Some((name, vis));
96 } 123 }
97 } 124 }
@@ -99,8 +126,8 @@ impl ItemScope {
99 } 126 }
100 127
101 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 128 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
102 self.visible.values().filter_map(|def| match def.take_types() { 129 self.types.values().filter_map(|(def, _)| match def {
103 Some(ModuleDefId::TraitId(t)) => Some(t), 130 ModuleDefId::TraitId(t) => Some(*t),
104 _ => None, 131 _ => None,
105 }) 132 })
106 } 133 }
@@ -123,26 +150,99 @@ impl ItemScope {
123 150
124 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 151 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
125 let mut changed = false; 152 let mut changed = false;
126 let existing = self.visible.entry(name).or_default();
127 153
128 if existing.types.is_none() && def.types.is_some() { 154 if let Some(types) = def.types {
129 existing.types = def.types; 155 self.types.entry(name.clone()).or_insert_with(|| {
130 changed = true; 156 changed = true;
157 types
158 });
131 } 159 }
132 if existing.values.is_none() && def.values.is_some() { 160 if let Some(values) = def.values {
133 existing.values = def.values; 161 self.values.entry(name.clone()).or_insert_with(|| {
134 changed = true; 162 changed = true;
163 values
164 });
165 }
166 if let Some(macros) = def.macros {
167 self.macros.entry(name.clone()).or_insert_with(|| {
168 changed = true;
169 macros
170 });
171 }
172
173 if def.is_none() {
174 if self.unresolved.insert(name) {
175 changed = true;
176 }
177 }
178
179 changed
180 }
181
182 pub(crate) fn push_res_with_import(
183 &mut self,
184 glob_imports: &mut PerNsGlobImports,
185 lookup: (LocalModuleId, Name),
186 def: PerNs,
187 def_import_type: ImportType,
188 ) -> bool {
189 let mut changed = false;
190
191 macro_rules! check_changed {
192 (
193 $changed:ident,
194 ( $this:ident / $def:ident ) . $field:ident,
195 $glob_imports:ident [ $lookup:ident ],
196 $def_import_type:ident
197 ) => {{
198 let existing = $this.$field.entry($lookup.1.clone());
199 match (existing, $def.$field) {
200 (Entry::Vacant(entry), Some(_)) => {
201 match $def_import_type {
202 ImportType::Glob => {
203 $glob_imports.$field.insert($lookup.clone());
204 }
205 ImportType::Named => {
206 $glob_imports.$field.remove(&$lookup);
207 }
208 }
209
210 if let Some(fld) = $def.$field {
211 entry.insert(fld);
212 }
213 $changed = true;
214 }
215 (Entry::Occupied(mut entry), Some(_))
216 if $glob_imports.$field.contains(&$lookup)
217 && matches!($def_import_type, ImportType::Named) =>
218 {
219 mark::hit!(import_shadowed);
220 $glob_imports.$field.remove(&$lookup);
221 if let Some(fld) = $def.$field {
222 entry.insert(fld);
223 }
224 $changed = true;
225 }
226 _ => {}
227 }
228 }};
135 } 229 }
136 if existing.macros.is_none() && def.macros.is_some() { 230
137 existing.macros = def.macros; 231 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
138 changed = true; 232 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
233 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
234
235 if def.is_none() {
236 if self.unresolved.insert(lookup.1) {
237 changed = true;
238 }
139 } 239 }
140 240
141 changed 241 changed
142 } 242 }
143 243
144 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 244 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
145 self.visible.iter().map(|(name, res)| (name.clone(), *res)) 245 self.entries().map(|(name, res)| (name.clone(), res))
146 } 246 }
147 247
148 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 248 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
@@ -203,4 +303,22 @@ impl ItemInNs {
203 ItemInNs::Macros(_) => None, 303 ItemInNs::Macros(_) => None,
204 } 304 }
205 } 305 }
306
307 /// Returns the crate defining this item (or `None` if `self` is built-in).
308 pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
309 Some(match self {
310 ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
311 ModuleDefId::ModuleId(id) => id.krate,
312 ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
313 ModuleDefId::AdtId(id) => id.module(db).krate,
314 ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
315 ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
316 ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
317 ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
318 ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
319 ModuleDefId::BuiltinType(_) => return None,
320 },
321 ItemInNs::Macros(id) => return id.krate,
322 })
323 }
206} 324}