Skip to main content

hir_def/
item_scope.rs

1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks.
3
4use std::{fmt, sync::LazyLock};
5
6use base_db::{Crate, SourceDatabase};
7use either::Either;
8use hir_expand::{AstId, MacroCallId, attrs::AttrId, name::Name};
9use indexmap::map::Entry;
10use itertools::Itertools;
11use la_arena::Idx;
12use rustc_hash::{FxHashMap, FxHashSet};
13use smallvec::SmallVec;
14use span::Edition;
15use stdx::{format_to, impl_from};
16use syntax::ast;
17use thin_vec::ThinVec;
18
19use crate::{
20    AdtId, BuiltinDeriveImplId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap,
21    HasModule, ImplId, Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
22    per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
23    visibility::Visibility,
24};
25
26#[derive(Debug, Default)]
27pub struct PerNsGlobImports {
28    types: FxHashSet<(ModuleId, Name)>,
29    values: FxHashSet<(ModuleId, Name)>,
30    macros: FxHashSet<(ModuleId, Name)>,
31}
32
33#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
34pub enum ImportOrExternCrate {
35    Glob(GlobId),
36    Import(ImportId),
37    ExternCrate(ExternCrateId),
38}
39
40impl_from!(ImportOrGlob { Glob, Import } for ImportOrExternCrate);
41
42impl ImportOrExternCrate {
43    pub fn import_or_glob(self) -> Option<ImportOrGlob> {
44        match self {
45            ImportOrExternCrate::Import(it) => Some(ImportOrGlob::Import(it)),
46            ImportOrExternCrate::Glob(it) => Some(ImportOrGlob::Glob(it)),
47            _ => None,
48        }
49    }
50
51    pub fn import(self) -> Option<ImportId> {
52        match self {
53            ImportOrExternCrate::Import(it) => Some(it),
54            _ => None,
55        }
56    }
57
58    pub fn glob(self) -> Option<GlobId> {
59        match self {
60            ImportOrExternCrate::Glob(id) => Some(id),
61            _ => None,
62        }
63    }
64
65    pub fn use_(self) -> Option<UseId> {
66        match self {
67            ImportOrExternCrate::Glob(id) => Some(id.use_),
68            ImportOrExternCrate::Import(id) => Some(id.use_),
69            _ => None,
70        }
71    }
72}
73
74#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
75pub enum ImportOrGlob {
76    Glob(GlobId),
77    Import(ImportId),
78}
79
80impl ImportOrGlob {
81    pub fn into_import(self) -> Option<ImportId> {
82        match self {
83            ImportOrGlob::Import(it) => Some(it),
84            _ => None,
85        }
86    }
87}
88
89#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
90pub enum ImportOrDef {
91    Import(ImportId),
92    Glob(GlobId),
93    ExternCrate(ExternCrateId),
94    Def(ModuleDefId),
95}
96
97impl_from!(ImportOrExternCrate { Import, Glob, ExternCrate } for ImportOrDef);
98impl_from!(ImportOrGlob { Import, Glob } for ImportOrDef);
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
101pub struct ImportId {
102    pub use_: UseId,
103    pub idx: Idx<ast::UseTree>,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
107pub struct GlobId {
108    pub use_: UseId,
109    pub idx: Idx<ast::UseTree>,
110}
111
112impl PerNsGlobImports {
113    pub(crate) fn contains_type(&self, module_id: ModuleId, name: Name) -> bool {
114        self.types.contains(&(module_id, name))
115    }
116    pub(crate) fn contains_value(&self, module_id: ModuleId, name: Name) -> bool {
117        self.values.contains(&(module_id, name))
118    }
119    pub(crate) fn contains_macro(&self, module_id: ModuleId, name: Name) -> bool {
120        self.macros.contains(&(module_id, name))
121    }
122}
123
124#[derive(Debug, Default, PartialEq, Eq)]
125pub struct ItemScope {
126    /// Defs visible in this scope. This includes `declarations`, but also
127    /// imports. The imports belong to this module and can be resolved by using them on
128    /// the `use_imports_*` fields.
129    types: FxIndexMap<Name, TypesItem>,
130    values: FxIndexMap<Name, ValuesItem>,
131    macros: FxIndexMap<Name, MacrosItem>,
132    unresolved: FxHashSet<Name>,
133
134    /// The defs declared in this scope. Each def has a single scope where it is
135    /// declared.
136    declarations: ThinVec<ModuleDefId>,
137
138    impls: ThinVec<(ImplId, /* trait impl */ bool)>,
139    builtin_derive_impls: ThinVec<BuiltinDeriveImplId>,
140    extern_blocks: ThinVec<ExternBlockId>,
141    unnamed_consts: ThinVec<ConstId>,
142    /// Traits imported via `use Trait as _;`.
143    unnamed_trait_imports: ThinVec<(TraitId, Item<()>)>,
144
145    // the resolutions of the imports of this scope
146    use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
147    use_imports_values: FxHashMap<ImportOrGlob, ImportOrDef>,
148    use_imports_macros: FxHashMap<ImportOrExternCrate, ImportOrDef>,
149
150    use_decls: ThinVec<UseId>,
151    extern_crate_decls: ThinVec<ExternCrateId>,
152    /// Macros visible in current module in legacy textual scope
153    ///
154    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
155    /// If it yields no result, then it turns to module scoped `macros`.
156    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
157    /// and only normal scoped `macros` will be searched in.
158    ///
159    /// Note that this automatically inherit macros defined textually before the definition of module itself.
160    ///
161    /// Module scoped macros will be inserted into `items` instead of here.
162    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
163    // be all resolved to the last one defined if shadowing happens.
164    legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 1]>>,
165    /// The attribute macro invocations in this scope.
166    attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
167    /// The macro invocations in this scope.
168    macro_invocations: FxHashMap<AstId<ast::MacroCall>, MacroCallId>,
169    /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
170    /// paired with the derive macro invocations for the specific attribute.
171    derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
172}
173
174#[derive(Debug, PartialEq, Eq)]
175struct DeriveMacroInvocation {
176    attr_id: AttrId,
177    /// The `#[derive]` call
178    attr_call_id: MacroCallId,
179    derive_call_ids: SmallVec<[Option<Either<MacroCallId, BuiltinDeriveImplId>>; 4]>,
180}
181
182pub(crate) static BUILTIN_SCOPE: LazyLock<FxIndexMap<Name, PerNs>> = LazyLock::new(|| {
183    BuiltinType::all_builtin_types()
184        .iter()
185        .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None)))
186        .collect()
187});
188
189/// Shadow mode for builtin type which can be shadowed by module.
190#[derive(Debug, Copy, Clone, PartialEq, Eq)]
191pub(crate) enum BuiltinShadowMode {
192    /// Prefer user-defined modules (or other types) over builtins.
193    Module,
194    /// Prefer builtins over user-defined modules (but not other types).
195    Other,
196}
197
198/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
199/// Other methods will only resolve values, types and module scoped macros only.
200impl ItemScope {
201    pub fn entries(&self) -> impl Iterator<Item = (&Name, PerNs)> + '_ {
202        // FIXME: shadowing
203        self.types
204            .keys()
205            .chain(self.values.keys())
206            .chain(self.macros.keys())
207            .chain(self.unresolved.iter())
208            .sorted()
209            .dedup()
210            .map(move |name| (name, self.get(name)))
211    }
212
213    pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrGlob>)> + '_ {
214        self.values.iter().map(|(n, &i)| (n, i))
215    }
216
217    pub fn types(
218        &self,
219    ) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrExternCrate>)> + '_ {
220        self.types.iter().map(|(n, &i)| (n, i))
221    }
222
223    pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportOrExternCrate>)> + '_ {
224        self.macros.iter().map(|(n, &i)| (n, i))
225    }
226
227    pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ {
228        self.use_imports_types
229            .keys()
230            .copied()
231            .chain(self.use_imports_macros.keys().copied())
232            .filter_map(ImportOrExternCrate::import_or_glob)
233            .chain(self.use_imports_values.keys().copied())
234            .filter_map(ImportOrGlob::into_import)
235            .sorted()
236            .dedup()
237    }
238
239    pub fn fully_resolve_import(&self, db: &dyn SourceDatabase, mut import: ImportId) -> PerNs {
240        let mut res = PerNs::none();
241
242        let mut scope = self;
243        while let Some(&m) = scope.use_imports_macros.get(&ImportOrExternCrate::Import(import)) {
244            match m {
245                ImportOrDef::Import(i) => {
246                    let module_id = i.use_.lookup(db).container;
247                    scope = &module_id.def_map(db)[module_id].scope;
248                    import = i;
249                }
250                ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
251                    res.macros = Some(Item { def, vis: Visibility::Public, import: None });
252                    break;
253                }
254                _ => break,
255            }
256        }
257        let mut scope = self;
258        while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) {
259            match m {
260                ImportOrDef::Import(i) => {
261                    let module_id = i.use_.lookup(db).container;
262                    scope = &module_id.def_map(db)[module_id].scope;
263                    import = i;
264                }
265                ImportOrDef::Def(def) => {
266                    res.types = Some(Item { def, vis: Visibility::Public, import: None });
267                    break;
268                }
269                _ => break,
270            }
271        }
272        let mut scope = self;
273        while let Some(&m) = scope.use_imports_values.get(&ImportOrGlob::Import(import)) {
274            match m {
275                ImportOrDef::Import(i) => {
276                    let module_id = i.use_.lookup(db).container;
277                    scope = &module_id.def_map(db)[module_id].scope;
278                    import = i;
279                }
280                ImportOrDef::Def(def) => {
281                    res.values = Some(Item { def, vis: Visibility::Public, import: None });
282                    break;
283                }
284                _ => break,
285            }
286        }
287        res
288    }
289
290    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
291        self.declarations.iter().copied()
292    }
293
294    pub fn extern_crate_decls(&self) -> impl ExactSizeIterator<Item = ExternCrateId> + '_ {
295        self.extern_crate_decls.iter().copied()
296    }
297
298    pub fn extern_blocks(&self) -> impl Iterator<Item = ExternBlockId> + '_ {
299        self.extern_blocks.iter().copied()
300    }
301
302    pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ {
303        self.use_decls.iter().copied()
304    }
305
306    pub fn impls(&self) -> impl ExactSizeIterator<Item = ImplId> + '_ {
307        self.impls.iter().map(|&(id, _)| id)
308    }
309
310    pub fn trait_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
311        self.impls.iter().filter(|&&(_, is_trait_impl)| is_trait_impl).map(|&(id, _)| id)
312    }
313
314    pub fn inherent_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
315        self.impls.iter().filter(|&&(_, is_trait_impl)| !is_trait_impl).map(|&(id, _)| id)
316    }
317
318    pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator<Item = BuiltinDeriveImplId> + '_ {
319        self.builtin_derive_impls.iter().copied()
320    }
321
322    pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
323        self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
324            self.derive_macros.values().flat_map(|it| {
325                it.iter().flat_map(|it| {
326                    it.derive_call_ids.iter().copied().flatten().flat_map(|it| it.left())
327                })
328            }),
329        )
330    }
331
332    pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
333        self.types.values().filter_map(|ns| match ns.def {
334            ModuleDefId::ModuleId(module) => Some((module, ns.vis)),
335            _ => None,
336        })
337    }
338
339    pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
340        self.unnamed_consts.iter().copied()
341    }
342
343    /// Iterate over all legacy textual scoped macros visible at the end of the module
344    pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ {
345        self.legacy_macros.iter().map(|(name, def)| (name, &**def))
346    }
347
348    /// Get a name from current module scope, legacy macros are not included
349    pub fn get(&self, name: &Name) -> PerNs {
350        PerNs {
351            types: self.types.get(name).copied(),
352            values: self.values.get(name).copied(),
353            macros: self.macros.get(name).copied(),
354        }
355    }
356
357    pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
358        self.types.get(name).map(|item| (item.def, item.vis))
359    }
360
361    pub(crate) fn makro(&self, name: &Name) -> Option<MacroId> {
362        self.macros.get(name).map(|item| item.def)
363    }
364
365    /// XXX: this is O(N) rather than O(1), try to not introduce new usages.
366    pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility, /*declared*/ bool)> {
367        match item {
368            ItemInNs::Macros(def) => self.macros.iter().find_map(|(name, other_def)| {
369                (other_def.def == def).then_some((name, other_def.vis, other_def.import.is_none()))
370            }),
371            ItemInNs::Types(def) => self.types.iter().find_map(|(name, other_def)| {
372                (other_def.def == def).then_some((name, other_def.vis, other_def.import.is_none()))
373            }),
374            ItemInNs::Values(def) => self.values.iter().find_map(|(name, other_def)| {
375                (other_def.def == def).then_some((name, other_def.vis, other_def.import.is_none()))
376            }),
377        }
378    }
379
380    /// XXX: this is O(N) rather than O(1), try to not introduce new usages.
381    pub(crate) fn names_of<T>(
382        &self,
383        item: ItemInNs,
384        mut cb: impl FnMut(&Name, Visibility, /*declared*/ bool) -> Option<T>,
385    ) -> Option<T> {
386        match item {
387            ItemInNs::Macros(def) => self
388                .macros
389                .iter()
390                .filter_map(|(name, other_def)| {
391                    (other_def.def == def).then_some((
392                        name,
393                        other_def.vis,
394                        other_def.import.is_none(),
395                    ))
396                })
397                .find_map(|(a, b, c)| cb(a, b, c)),
398            ItemInNs::Types(def) => self
399                .types
400                .iter()
401                .filter_map(|(name, other_def)| {
402                    (other_def.def == def).then_some((
403                        name,
404                        other_def.vis,
405                        other_def.import.is_none(),
406                    ))
407                })
408                .find_map(|(a, b, c)| cb(a, b, c)),
409            ItemInNs::Values(def) => self
410                .values
411                .iter()
412                .filter_map(|(name, other_def)| {
413                    (other_def.def == def).then_some((
414                        name,
415                        other_def.vis,
416                        other_def.import.is_none(),
417                    ))
418                })
419                .find_map(|(a, b, c)| cb(a, b, c)),
420        }
421    }
422
423    pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
424        self.types
425            .values()
426            .filter_map(|def| match def.def {
427                ModuleDefId::TraitId(t) => Some(t),
428                _ => None,
429            })
430            .chain(self.unnamed_trait_imports.iter().map(|&(t, _)| t))
431    }
432
433    pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
434        self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
435            self.unnamed_trait_imports.iter().map(|(tr, trait_)| {
436                (
437                    None,
438                    PerNs::types(
439                        ModuleDefId::TraitId(*tr),
440                        trait_.vis,
441                        trait_.import.map(ImportOrExternCrate::Import),
442                    ),
443                )
444            }),
445        )
446    }
447
448    pub fn macro_invoc(&self, call: AstId<ast::MacroCall>) -> Option<MacroCallId> {
449        self.macro_invocations.get(&call).copied()
450    }
451
452    pub fn iter_macro_invoc(&self) -> impl Iterator<Item = (&AstId<ast::MacroCall>, &MacroCallId)> {
453        self.macro_invocations.iter()
454    }
455}
456
457impl ItemScope {
458    pub(crate) fn declare(&mut self, def: ModuleDefId) {
459        self.declarations.push(def)
460    }
461
462    pub(crate) fn remove_from_value_ns(&mut self, name: &Name, def: ModuleDefId) {
463        // predicate needed since a different item with the same name may be registered instead,
464        // leading to `shift_remove` removing the wrong item.
465        if self.values.get(name).is_some_and(|entry| entry.def == def) {
466            let _ = self.values.shift_remove(name);
467        }
468    }
469
470    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
471        self.legacy_macros.get(name).map(|it| &**it)
472    }
473
474    pub(crate) fn define_impl(&mut self, imp: ImplId, is_trait_impl: bool) {
475        self.impls.push((imp, is_trait_impl));
476    }
477
478    pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) {
479        self.builtin_derive_impls.push(imp);
480    }
481
482    pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) {
483        self.extern_blocks.push(extern_block);
484    }
485
486    pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) {
487        self.extern_crate_decls.push(extern_crate);
488    }
489
490    pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
491        self.unnamed_consts.push(konst);
492    }
493
494    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroId) {
495        self.legacy_macros.entry(name).or_default().push(mac);
496    }
497
498    pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
499        self.attr_macros.insert(item, call);
500    }
501
502    pub(crate) fn add_macro_invoc(&mut self, call: AstId<ast::MacroCall>, call_id: MacroCallId) {
503        self.macro_invocations.insert(call, call_id);
504    }
505
506    pub fn attr_macro_invocs(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
507        self.attr_macros.iter().map(|(k, v)| (*k, *v))
508    }
509
510    pub(crate) fn set_derive_macro_invoc(
511        &mut self,
512        adt: AstId<ast::Adt>,
513        call: Either<MacroCallId, BuiltinDeriveImplId>,
514        id: AttrId,
515        idx: usize,
516    ) {
517        if let Some(derives) = self.derive_macros.get_mut(&adt)
518            && let Some(DeriveMacroInvocation { derive_call_ids, .. }) =
519                derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id)
520        {
521            derive_call_ids[idx] = Some(call);
522        }
523    }
524
525    /// We are required to set this up front as derive invocation recording happens out of order
526    /// due to the fixed pointer iteration loop being able to record some derives later than others
527    /// independent of their indices.
528    pub(crate) fn init_derive_attribute(
529        &mut self,
530        adt: AstId<ast::Adt>,
531        attr_id: AttrId,
532        attr_call_id: MacroCallId,
533        mut derive_call_ids: SmallVec<[Option<Either<MacroCallId, BuiltinDeriveImplId>>; 4]>,
534    ) {
535        derive_call_ids.shrink_to_fit();
536        self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
537            attr_id,
538            attr_call_id,
539            derive_call_ids,
540        });
541    }
542
543    pub fn derive_macro_invocs(
544        &self,
545    ) -> impl Iterator<
546        Item = (
547            AstId<ast::Adt>,
548            impl Iterator<
549                Item = (AttrId, MacroCallId, &[Option<Either<MacroCallId, BuiltinDeriveImplId>>]),
550            >,
551        ),
552    > + '_ {
553        self.derive_macros.iter().map(|(k, v)| {
554            (
555                *k,
556                v.iter().map(|DeriveMacroInvocation { attr_id, attr_call_id, derive_call_ids }| {
557                    (*attr_id, *attr_call_id, &**derive_call_ids)
558                }),
559            )
560        })
561    }
562
563    pub fn derive_macro_invoc(
564        &self,
565        ast_id: AstId<ast::Adt>,
566        attr_id: AttrId,
567    ) -> Option<MacroCallId> {
568        Some(self.derive_macros.get(&ast_id)?.iter().find(|it| it.attr_id == attr_id)?.attr_call_id)
569    }
570
571    // FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
572    pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
573        self.unnamed_trait_imports.iter().find(|&&(t, _)| t == tr).map(|(_, trait_)| trait_.vis)
574    }
575
576    pub(crate) fn push_unnamed_trait(
577        &mut self,
578        tr: TraitId,
579        vis: Visibility,
580        import: Option<ImportId>,
581    ) {
582        self.unnamed_trait_imports.push((tr, Item { def: (), vis, import }));
583    }
584
585    pub(crate) fn push_res_with_import(
586        &mut self,
587        glob_imports: &mut PerNsGlobImports,
588        lookup: (ModuleId, Name),
589        def: PerNs,
590        import: Option<ImportOrExternCrate>,
591    ) -> bool {
592        let mut changed = false;
593
594        // FIXME: Document and simplify this
595
596        if let Some(mut fld) = def.types {
597            let existing = self.types.entry(lookup.1.clone());
598            match existing {
599                Entry::Vacant(entry) => {
600                    match import {
601                        Some(ImportOrExternCrate::Glob(_)) => {
602                            glob_imports.types.insert(lookup.clone());
603                        }
604                        _ => _ = glob_imports.types.remove(&lookup),
605                    }
606                    let prev = std::mem::replace(&mut fld.import, import);
607                    if let Some(import) = import {
608                        self.use_imports_types
609                            .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
610                    }
611                    entry.insert(fld);
612                    changed = true;
613                }
614                Entry::Occupied(mut entry) => {
615                    match import {
616                        Some(ImportOrExternCrate::Glob(..)) => {
617                            // Multiple globs may import the same item and they may
618                            // override visibility from previously resolved globs. This is
619                            // currently handled by `DefCollector`, because we need to
620                            // compute the max visibility for items and we need `DefMap`
621                            // for that.
622                        }
623                        _ => {
624                            // A non-glob import either shadows a glob import of the same
625                            // name, or re-resolves a stale binding it recorded earlier.
626                            if glob_imports.types.remove(&lookup)
627                                || entry.get().is_reresolved_by(&fld.def, import)
628                            {
629                                let prev = std::mem::replace(&mut fld.import, import);
630                                if let Some(import) = import {
631                                    self.use_imports_types.insert(
632                                        import,
633                                        prev.map_or(ImportOrDef::Def(fld.def), Into::into),
634                                    );
635                                }
636                                cov_mark::hit!(import_shadowed);
637                                entry.insert(fld);
638                                changed = true;
639                            }
640                        }
641                    }
642                }
643            }
644        }
645
646        if let Some(mut fld) = def.values {
647            let existing = self.values.entry(lookup.1.clone());
648            match existing {
649                Entry::Vacant(entry) => {
650                    match import {
651                        Some(ImportOrExternCrate::Glob(_)) => {
652                            glob_imports.values.insert(lookup.clone());
653                        }
654                        _ => _ = glob_imports.values.remove(&lookup),
655                    }
656                    let import = import.and_then(ImportOrExternCrate::import_or_glob);
657                    let prev = std::mem::replace(&mut fld.import, import);
658                    if let Some(import) = import {
659                        self.use_imports_values
660                            .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
661                    }
662                    entry.insert(fld);
663                    changed = true;
664                }
665                Entry::Occupied(mut entry)
666                    if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
667                {
668                    let import = import.and_then(ImportOrExternCrate::import_or_glob);
669                    if glob_imports.values.remove(&lookup)
670                        || entry.get().is_reresolved_by(&fld.def, import)
671                    {
672                        cov_mark::hit!(import_shadowed);
673
674                        let prev = std::mem::replace(&mut fld.import, import);
675                        if let Some(import) = import {
676                            self.use_imports_values
677                                .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
678                        }
679                        entry.insert(fld);
680                        changed = true;
681                    }
682                }
683                _ => {}
684            }
685        }
686
687        if let Some(mut fld) = def.macros {
688            let existing = self.macros.entry(lookup.1.clone());
689            match existing {
690                Entry::Vacant(entry) => {
691                    match import {
692                        Some(ImportOrExternCrate::Glob(_)) => {
693                            glob_imports.macros.insert(lookup.clone());
694                        }
695                        _ => _ = glob_imports.macros.remove(&lookup),
696                    }
697                    let prev = std::mem::replace(&mut fld.import, import);
698                    if let Some(import) = import {
699                        self.use_imports_macros.insert(
700                            import,
701                            prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
702                        );
703                    }
704                    entry.insert(fld);
705                    changed = true;
706                }
707                Entry::Occupied(mut entry)
708                    if !matches!(import, Some(ImportOrExternCrate::Glob(..)))
709                        && (glob_imports.macros.remove(&lookup)
710                            || entry.get().is_reresolved_by(&fld.def, import)) =>
711                {
712                    cov_mark::hit!(import_shadowed);
713                    let prev = std::mem::replace(&mut fld.import, import);
714                    if let Some(import) = import {
715                        self.use_imports_macros.insert(
716                            import,
717                            prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
718                        );
719                    }
720                    entry.insert(fld);
721                    changed = true;
722                }
723                _ => {}
724            }
725        }
726
727        if def.is_none() && self.unresolved.insert(lookup.1) {
728            changed = true;
729        }
730
731        changed
732    }
733
734    /// Marks everything that is not a procedural macro as private to `this_module`.
735    pub(crate) fn censor_non_proc_macros(&mut self, krate: Crate) {
736        self.types
737            .values_mut()
738            .map(|def| &mut def.vis)
739            .chain(self.values.values_mut().map(|def| &mut def.vis))
740            .chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis))
741            .for_each(|vis| *vis = Visibility::PubCrate(krate));
742
743        for mac in self.macros.values_mut() {
744            if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
745                continue;
746            }
747            mac.vis = Visibility::PubCrate(krate)
748        }
749    }
750
751    pub(crate) fn dump(&self, db: &dyn SourceDatabase, buf: &mut String) {
752        let mut entries: Vec<_> = self.resolutions().collect();
753        entries.sort_by_key(|(name, _)| name.clone());
754
755        let print_macro_sub_ns = |buf: &mut String, macro_id: MacroId| {
756            let styles = crate::nameres::macro_styles_from_id(db, macro_id);
757            if styles.contains(MacroCallStyles::FN_LIKE) {
758                buf.push('!');
759            }
760            if styles.contains(MacroCallStyles::ATTR) || styles.contains(MacroCallStyles::DERIVE) {
761                buf.push('#');
762            }
763        };
764
765        for (name, def) in entries {
766            let display_name: &dyn fmt::Display = match &name {
767                Some(name) => &name.display(db, Edition::LATEST),
768                None => &"_",
769            };
770            format_to!(buf, "- {display_name} :");
771
772            if let Some(Item { import, .. }) = def.types {
773                buf.push_str(" type");
774                match import {
775                    Some(ImportOrExternCrate::Import(_)) => buf.push_str(" (import)"),
776                    Some(ImportOrExternCrate::Glob(_)) => buf.push_str(" (glob)"),
777                    Some(ImportOrExternCrate::ExternCrate(_)) => buf.push_str(" (extern)"),
778                    None => (),
779                }
780            }
781            if let Some(Item { import, .. }) = def.values {
782                buf.push_str(" value");
783                match import {
784                    Some(ImportOrGlob::Import(_)) => buf.push_str(" (import)"),
785                    Some(ImportOrGlob::Glob(_)) => buf.push_str(" (glob)"),
786                    None => (),
787                }
788            }
789            if let Some(Item { def: macro_id, import, .. }) = def.macros {
790                buf.push_str(" macro");
791                print_macro_sub_ns(buf, macro_id);
792                match import {
793                    Some(ImportOrExternCrate::Import(_)) => buf.push_str(" (import)"),
794                    Some(ImportOrExternCrate::Glob(_)) => buf.push_str(" (glob)"),
795                    Some(ImportOrExternCrate::ExternCrate(_)) => buf.push_str(" (extern)"),
796                    None => (),
797                }
798            }
799            if def.is_none() {
800                buf.push_str(" _");
801            }
802
803            buf.push('\n');
804        }
805
806        // Also dump legacy-textual-scope macros visible at the _end_ of the scope.
807        //
808        // For tests involving a cursor position, this might include macros that
809        // are _not_ visible at the cursor position.
810        let mut legacy_macros = self.legacy_macros().collect::<Vec<_>>();
811        legacy_macros.sort_by(|(a, _), (b, _)| Ord::cmp(a, b));
812        for (name, macros) in legacy_macros {
813            format_to!(buf, "- (legacy) {} :", name.display(db, Edition::LATEST));
814            for &macro_id in macros {
815                buf.push_str(" macro");
816                print_macro_sub_ns(buf, macro_id);
817            }
818            buf.push('\n');
819        }
820    }
821
822    pub(crate) fn shrink_to_fit(&mut self) {
823        // Exhaustive match to require handling new fields.
824        let Self {
825            types,
826            values,
827            macros,
828            unresolved,
829            declarations,
830            impls,
831            builtin_derive_impls,
832            unnamed_consts,
833            unnamed_trait_imports,
834            legacy_macros,
835            attr_macros,
836            derive_macros,
837            extern_crate_decls,
838            use_decls,
839            use_imports_values,
840            use_imports_types,
841            use_imports_macros,
842            macro_invocations,
843            extern_blocks,
844        } = self;
845        extern_blocks.shrink_to_fit();
846        types.shrink_to_fit();
847        values.shrink_to_fit();
848        macros.shrink_to_fit();
849        use_imports_types.shrink_to_fit();
850        use_imports_values.shrink_to_fit();
851        use_imports_macros.shrink_to_fit();
852        unresolved.shrink_to_fit();
853        declarations.shrink_to_fit();
854        impls.shrink_to_fit();
855        builtin_derive_impls.shrink_to_fit();
856        unnamed_consts.shrink_to_fit();
857        unnamed_trait_imports.shrink_to_fit();
858        legacy_macros.shrink_to_fit();
859        attr_macros.shrink_to_fit();
860        derive_macros.shrink_to_fit();
861        extern_crate_decls.shrink_to_fit();
862        use_decls.shrink_to_fit();
863        macro_invocations.shrink_to_fit();
864    }
865}
866
867// These methods are a temporary measure only meant to be used by `DefCollector::push_res_and_update_glob_vis()`.
868impl ItemScope {
869    pub(crate) fn update_visibility_types(&mut self, name: &Name, vis: Visibility) {
870        let res =
871            self.types.get_mut(name).expect("tried to update visibility of non-existent type");
872        res.vis = vis;
873    }
874
875    pub(crate) fn update_visibility_values(&mut self, name: &Name, vis: Visibility) {
876        let res =
877            self.values.get_mut(name).expect("tried to update visibility of non-existent value");
878        res.vis = vis;
879    }
880
881    pub(crate) fn update_visibility_macros(&mut self, name: &Name, vis: Visibility) {
882        let res =
883            self.macros.get_mut(name).expect("tried to update visibility of non-existent macro");
884        res.vis = vis;
885    }
886
887    pub(crate) fn update_def_types(&mut self, name: &Name, def: ModuleDefId, vis: Visibility) {
888        let res = self.types.get_mut(name).expect("tried to update def of non-existent type");
889        res.def = def;
890        res.vis = vis;
891    }
892
893    pub(crate) fn update_def_values(&mut self, name: &Name, def: ModuleDefId, vis: Visibility) {
894        let res = self.values.get_mut(name).expect("tried to update def of non-existent value");
895        res.def = def;
896        res.vis = vis;
897    }
898
899    pub(crate) fn update_def_macros(&mut self, name: &Name, def: MacroId, vis: Visibility) {
900        let res = self.macros.get_mut(name).expect("tried to update def of non-existent macro");
901        res.def = def;
902        res.vis = vis;
903    }
904}
905
906impl PerNs {
907    pub(crate) fn from_def(
908        def: ModuleDefId,
909        vis: Visibility,
910        value_ns_ctor_vis: Option<Visibility>,
911        import: Option<ImportOrExternCrate>,
912    ) -> PerNs {
913        match def {
914            ModuleDefId::ModuleId(_) => PerNs::types(def, vis, import),
915            ModuleDefId::FunctionId(_) => {
916                PerNs::values(def, vis, import.and_then(ImportOrExternCrate::import_or_glob))
917            }
918            ModuleDefId::AdtId(adt) => match adt {
919                AdtId::UnionId(_) => PerNs::types(def, vis, import),
920                AdtId::EnumId(_) => PerNs::types(def, vis, import),
921                AdtId::StructId(_) => match value_ns_ctor_vis {
922                    Some(value_ns_ctor_vis) => PerNs {
923                        types: Some(Item { def, vis, import }),
924                        values: Some(Item {
925                            def,
926                            vis: value_ns_ctor_vis,
927                            import: import.and_then(ImportOrExternCrate::import_or_glob),
928                        }),
929                        macros: None,
930                    },
931                    None => PerNs::types(def, vis, import),
932                },
933            },
934            ModuleDefId::EnumVariantId(_) => match value_ns_ctor_vis {
935                Some(value_ns_ctor_vis) => PerNs {
936                    types: Some(Item { def, vis, import }),
937                    values: Some(Item {
938                        def,
939                        vis: value_ns_ctor_vis,
940                        import: import.and_then(ImportOrExternCrate::import_or_glob),
941                    }),
942                    macros: None,
943                },
944                None => PerNs::types(def, vis, import),
945            },
946            ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => {
947                PerNs::values(def, vis, import.and_then(ImportOrExternCrate::import_or_glob))
948            }
949            ModuleDefId::TraitId(_) => PerNs::types(def, vis, import),
950            ModuleDefId::TypeAliasId(_) => PerNs::types(def, vis, import),
951            ModuleDefId::BuiltinType(_) => PerNs::types(def, vis, import),
952            ModuleDefId::MacroId(mac) => PerNs::macros(mac, vis, import),
953        }
954    }
955}
956
957#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
958pub enum ItemInNs {
959    Types(ModuleDefId),
960    Values(ModuleDefId),
961    Macros(MacroId),
962}
963
964impl ItemInNs {
965    pub fn as_module_def_id(self) -> Option<ModuleDefId> {
966        match self {
967            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
968            ItemInNs::Macros(_) => None,
969        }
970    }
971
972    /// Returns the crate defining this item (or `None` if `self` is built-in).
973    pub fn krate(&self, db: &dyn SourceDatabase) -> Option<Crate> {
974        self.module(db).map(|module_id| module_id.krate(db))
975    }
976
977    pub fn module(&self, db: &dyn SourceDatabase) -> Option<ModuleId> {
978        match self {
979            ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db),
980            ItemInNs::Macros(id) => Some(id.module(db)),
981        }
982    }
983}