• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Describes items defined or visible (ie, imported) in a certain scope.
2 //! This is shared between modules and blocks.
3 
4 use std::collections::hash_map::Entry;
5 
6 use base_db::CrateId;
7 use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
8 use itertools::Itertools;
9 use once_cell::sync::Lazy;
10 use profile::Count;
11 use rustc_hash::{FxHashMap, FxHashSet};
12 use smallvec::{smallvec, SmallVec};
13 use stdx::format_to;
14 use syntax::ast;
15 
16 use crate::{
17     db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, HasModule,
18     ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
19 };
20 
21 #[derive(Copy, Clone, Debug)]
22 pub(crate) enum ImportType {
23     Glob,
24     Named,
25 }
26 
27 #[derive(Debug, Default)]
28 pub struct PerNsGlobImports {
29     types: FxHashSet<(LocalModuleId, Name)>,
30     values: FxHashSet<(LocalModuleId, Name)>,
31     macros: FxHashSet<(LocalModuleId, Name)>,
32 }
33 
34 #[derive(Debug, Default, PartialEq, Eq)]
35 pub struct ItemScope {
36     _c: Count<Self>,
37 
38     /// Defs visible in this scope. This includes `declarations`, but also
39     /// imports.
40     types: FxHashMap<Name, (ModuleDefId, Visibility)>,
41     values: FxHashMap<Name, (ModuleDefId, Visibility)>,
42     macros: FxHashMap<Name, (MacroId, Visibility)>,
43     unresolved: FxHashSet<Name>,
44 
45     /// The defs declared in this scope. Each def has a single scope where it is
46     /// declared.
47     declarations: Vec<ModuleDefId>,
48 
49     impls: Vec<ImplId>,
50     unnamed_consts: Vec<ConstId>,
51     /// Traits imported via `use Trait as _;`.
52     unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
53     /// Macros visible in current module in legacy textual scope
54     ///
55     /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
56     /// If it yields no result, then it turns to module scoped `macros`.
57     /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
58     /// and only normal scoped `macros` will be searched in.
59     ///
60     /// Note that this automatically inherit macros defined textually before the definition of module itself.
61     ///
62     /// Module scoped macros will be inserted into `items` instead of here.
63     // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
64     // be all resolved to the last one defined if shadowing happens.
65     legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 1]>>,
66     /// The derive macro invocations in this scope.
67     attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
68     /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
69     /// paired with the derive macro invocations for the specific attribute.
70     derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
71 }
72 
73 #[derive(Debug, PartialEq, Eq)]
74 struct DeriveMacroInvocation {
75     attr_id: AttrId,
76     attr_call_id: MacroCallId,
77     derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
78 }
79 
80 pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
81     BuiltinType::ALL
82         .iter()
83         .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
84         .collect()
85 });
86 
87 /// Shadow mode for builtin type which can be shadowed by module.
88 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
89 pub(crate) enum BuiltinShadowMode {
90     /// Prefer user-defined modules (or other types) over builtins.
91     Module,
92     /// Prefer builtins over user-defined modules (but not other types).
93     Other,
94 }
95 
96 /// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
97 /// Other methods will only resolve values, types and module scoped macros only.
98 impl ItemScope {
entries(&self) -> impl Iterator<Item = (&Name, PerNs)> + '_99     pub fn entries(&self) -> impl Iterator<Item = (&Name, PerNs)> + '_ {
100         // FIXME: shadowing
101         self.types
102             .keys()
103             .chain(self.values.keys())
104             .chain(self.macros.keys())
105             .chain(self.unresolved.iter())
106             .sorted()
107             .unique()
108             .map(move |name| (name, self.get(name)))
109     }
110 
declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_111     pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
112         self.declarations.iter().copied()
113     }
114 
impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_115     pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
116         self.impls.iter().copied()
117     }
118 
values( &self, ) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_119     pub fn values(
120         &self,
121     ) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
122         self.values.values().copied()
123     }
124 
types( &self, ) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_125     pub fn types(
126         &self,
127     ) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
128         self.types.values().copied()
129     }
130 
unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_131     pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
132         self.unnamed_consts.iter().copied()
133     }
134 
135     /// Iterate over all module scoped macros
macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_136     pub(crate) fn macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
137         self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
138     }
139 
140     /// Iterate over all legacy textual scoped macros visible at the end of the module
legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_141     pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ {
142         self.legacy_macros.iter().map(|(name, def)| (name, &**def))
143     }
144 
145     /// Get a name from current module scope, legacy macros are not included
get(&self, name: &Name) -> PerNs146     pub(crate) fn get(&self, name: &Name) -> PerNs {
147         PerNs {
148             types: self.types.get(name).copied(),
149             values: self.values.get(name).copied(),
150             macros: self.macros.get(name).copied(),
151         }
152     }
153 
type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)>154     pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
155         self.types.get(name).copied()
156     }
157 
158     /// XXX: this is O(N) rather than O(1), try to not introduce new usages.
name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)>159     pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
160         let (def, mut iter) = match item {
161             ItemInNs::Macros(def) => {
162                 return self.macros.iter().find_map(|(name, &(other_def, vis))| {
163                     (other_def == def).then_some((name, vis))
164                 });
165             }
166             ItemInNs::Types(def) => (def, self.types.iter()),
167             ItemInNs::Values(def) => (def, self.values.iter()),
168         };
169         iter.find_map(|(name, &(other_def, vis))| (other_def == def).then_some((name, vis)))
170     }
171 
traits(&self) -> impl Iterator<Item = TraitId> + '_172     pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
173         self.types
174             .values()
175             .filter_map(|&(def, _)| match def {
176                 ModuleDefId::TraitId(t) => Some(t),
177                 _ => None,
178             })
179             .chain(self.unnamed_trait_imports.keys().copied())
180     }
181 
declare(&mut self, def: ModuleDefId)182     pub(crate) fn declare(&mut self, def: ModuleDefId) {
183         self.declarations.push(def)
184     }
185 
get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]>186     pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
187         self.legacy_macros.get(name).map(|it| &**it)
188     }
189 
define_impl(&mut self, imp: ImplId)190     pub(crate) fn define_impl(&mut self, imp: ImplId) {
191         self.impls.push(imp)
192     }
193 
define_unnamed_const(&mut self, konst: ConstId)194     pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
195         self.unnamed_consts.push(konst);
196     }
197 
define_legacy_macro(&mut self, name: Name, mac: MacroId)198     pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroId) {
199         self.legacy_macros.entry(name).or_default().push(mac);
200     }
201 
add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId)202     pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
203         self.attr_macros.insert(item, call);
204     }
205 
attr_macro_invocs( &self, ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_206     pub(crate) fn attr_macro_invocs(
207         &self,
208     ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
209         self.attr_macros.iter().map(|(k, v)| (*k, *v))
210     }
211 
set_derive_macro_invoc( &mut self, adt: AstId<ast::Adt>, call: MacroCallId, id: AttrId, idx: usize, )212     pub(crate) fn set_derive_macro_invoc(
213         &mut self,
214         adt: AstId<ast::Adt>,
215         call: MacroCallId,
216         id: AttrId,
217         idx: usize,
218     ) {
219         if let Some(derives) = self.derive_macros.get_mut(&adt) {
220             if let Some(DeriveMacroInvocation { derive_call_ids, .. }) =
221                 derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id)
222             {
223                 derive_call_ids[idx] = Some(call);
224             }
225         }
226     }
227 
228     /// We are required to set this up front as derive invocation recording happens out of order
229     /// due to the fixed pointer iteration loop being able to record some derives later than others
230     /// independent of their indices.
init_derive_attribute( &mut self, adt: AstId<ast::Adt>, attr_id: AttrId, attr_call_id: MacroCallId, len: usize, )231     pub(crate) fn init_derive_attribute(
232         &mut self,
233         adt: AstId<ast::Adt>,
234         attr_id: AttrId,
235         attr_call_id: MacroCallId,
236         len: usize,
237     ) {
238         self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
239             attr_id,
240             attr_call_id,
241             derive_call_ids: smallvec![None; len],
242         });
243     }
244 
derive_macro_invocs( &self, ) -> impl Iterator< Item = ( AstId<ast::Adt>, impl Iterator<Item = (AttrId, MacroCallId, &[Option<MacroCallId>])>, ), > + '_245     pub(crate) fn derive_macro_invocs(
246         &self,
247     ) -> impl Iterator<
248         Item = (
249             AstId<ast::Adt>,
250             impl Iterator<Item = (AttrId, MacroCallId, &[Option<MacroCallId>])>,
251         ),
252     > + '_ {
253         self.derive_macros.iter().map(|(k, v)| {
254             (
255                 *k,
256                 v.iter().map(|DeriveMacroInvocation { attr_id, attr_call_id, derive_call_ids }| {
257                     (*attr_id, *attr_call_id, &**derive_call_ids)
258                 }),
259             )
260         })
261     }
262 
unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility>263     pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
264         self.unnamed_trait_imports.get(&tr).copied()
265     }
266 
push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility)267     pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
268         self.unnamed_trait_imports.insert(tr, vis);
269     }
270 
push_res_with_import( &mut self, glob_imports: &mut PerNsGlobImports, lookup: (LocalModuleId, Name), def: PerNs, def_import_type: ImportType, ) -> bool271     pub(crate) fn push_res_with_import(
272         &mut self,
273         glob_imports: &mut PerNsGlobImports,
274         lookup: (LocalModuleId, Name),
275         def: PerNs,
276         def_import_type: ImportType,
277     ) -> bool {
278         let mut changed = false;
279 
280         macro_rules! check_changed {
281             (
282                 $changed:ident,
283                 ( $this:ident / $def:ident ) . $field:ident,
284                 $glob_imports:ident [ $lookup:ident ],
285                 $def_import_type:ident
286             ) => {{
287                 if let Some(fld) = $def.$field {
288                     let existing = $this.$field.entry($lookup.1.clone());
289                     match existing {
290                         Entry::Vacant(entry) => {
291                             match $def_import_type {
292                                 ImportType::Glob => {
293                                     $glob_imports.$field.insert($lookup.clone());
294                                 }
295                                 ImportType::Named => {
296                                     $glob_imports.$field.remove(&$lookup);
297                                 }
298                             }
299 
300                             entry.insert(fld);
301                             $changed = true;
302                         }
303                         Entry::Occupied(mut entry)
304                             if matches!($def_import_type, ImportType::Named) =>
305                         {
306                             if $glob_imports.$field.remove(&$lookup) {
307                                 cov_mark::hit!(import_shadowed);
308                                 entry.insert(fld);
309                                 $changed = true;
310                             }
311                         }
312                         _ => {}
313                     }
314                 }
315             }};
316         }
317 
318         check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
319         check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
320         check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
321 
322         if def.is_none() && self.unresolved.insert(lookup.1) {
323             changed = true;
324         }
325 
326         changed
327     }
328 
resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_329     pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
330         self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
331             self.unnamed_trait_imports
332                 .iter()
333                 .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
334         )
335     }
336 
337     /// Marks everything that is not a procedural macro as private to `this_module`.
censor_non_proc_macros(&mut self, this_module: ModuleId)338     pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
339         self.types
340             .values_mut()
341             .chain(self.values.values_mut())
342             .map(|(_, v)| v)
343             .chain(self.unnamed_trait_imports.values_mut())
344             .for_each(|vis| *vis = Visibility::Module(this_module));
345 
346         for (mac, vis) in self.macros.values_mut() {
347             if let MacroId::ProcMacroId(_) = mac {
348                 // FIXME: Technically this is insufficient since reexports of proc macros are also
349                 // forbidden. Practically nobody does that.
350                 continue;
351             }
352 
353             *vis = Visibility::Module(this_module);
354         }
355     }
356 
dump(&self, db: &dyn ExpandDatabase, buf: &mut String)357     pub(crate) fn dump(&self, db: &dyn ExpandDatabase, buf: &mut String) {
358         let mut entries: Vec<_> = self.resolutions().collect();
359         entries.sort_by_key(|(name, _)| name.clone());
360 
361         for (name, def) in entries {
362             format_to!(
363                 buf,
364                 "{}:",
365                 name.map_or("_".to_string(), |name| name.display(db).to_string())
366             );
367 
368             if def.types.is_some() {
369                 buf.push_str(" t");
370             }
371             if def.values.is_some() {
372                 buf.push_str(" v");
373             }
374             if def.macros.is_some() {
375                 buf.push_str(" m");
376             }
377             if def.is_none() {
378                 buf.push_str(" _");
379             }
380 
381             buf.push('\n');
382         }
383     }
384 
shrink_to_fit(&mut self)385     pub(crate) fn shrink_to_fit(&mut self) {
386         // Exhaustive match to require handling new fields.
387         let Self {
388             _c: _,
389             types,
390             values,
391             macros,
392             unresolved,
393             declarations,
394             impls,
395             unnamed_consts,
396             unnamed_trait_imports,
397             legacy_macros,
398             attr_macros,
399             derive_macros,
400         } = self;
401         types.shrink_to_fit();
402         values.shrink_to_fit();
403         macros.shrink_to_fit();
404         unresolved.shrink_to_fit();
405         declarations.shrink_to_fit();
406         impls.shrink_to_fit();
407         unnamed_consts.shrink_to_fit();
408         unnamed_trait_imports.shrink_to_fit();
409         legacy_macros.shrink_to_fit();
410         attr_macros.shrink_to_fit();
411         derive_macros.shrink_to_fit();
412     }
413 }
414 
415 impl PerNs {
from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs416     pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
417         match def {
418             ModuleDefId::ModuleId(_) => PerNs::types(def, v),
419             ModuleDefId::FunctionId(_) => PerNs::values(def, v),
420             ModuleDefId::AdtId(adt) => match adt {
421                 AdtId::UnionId(_) => PerNs::types(def, v),
422                 AdtId::EnumId(_) => PerNs::types(def, v),
423                 AdtId::StructId(_) => {
424                     if has_constructor {
425                         PerNs::both(def, def, v)
426                     } else {
427                         PerNs::types(def, v)
428                     }
429                 }
430             },
431             ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
432             ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
433             ModuleDefId::TraitId(_) => PerNs::types(def, v),
434             ModuleDefId::TraitAliasId(_) => PerNs::types(def, v),
435             ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
436             ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
437             ModuleDefId::MacroId(mac) => PerNs::macros(mac, v),
438         }
439     }
440 }
441 
442 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
443 pub enum ItemInNs {
444     Types(ModuleDefId),
445     Values(ModuleDefId),
446     Macros(MacroId),
447 }
448 
449 impl ItemInNs {
as_module_def_id(self) -> Option<ModuleDefId>450     pub fn as_module_def_id(self) -> Option<ModuleDefId> {
451         match self {
452             ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
453             ItemInNs::Macros(_) => None,
454         }
455     }
456 
457     /// Returns the crate defining this item (or `None` if `self` is built-in).
krate(&self, db: &dyn DefDatabase) -> Option<CrateId>458     pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
459         match self {
460             ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
461             ItemInNs::Macros(id) => Some(id.module(db).krate),
462         }
463     }
464 
module(&self, db: &dyn DefDatabase) -> Option<ModuleId>465     pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
466         match self {
467             ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db),
468             ItemInNs::Macros(id) => Some(id.module(db)),
469         }
470     }
471 }
472