Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Defines database & queries for name resolution.
use base_db::{Crate, SourceDatabase};
use hir_expand::{
    EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
};
use salsa::{Durability, Setter};
use triomphe::Arc;

use crate::{
    AssocItemId, AttrDefId, MacroExpander, MacroId, MacroRulesLocFlags, TraitId,
    attrs::AttrFlags,
    item_tree::{ItemTree, file_item_tree},
    nameres::crate_def_map,
    visibility::{self, Visibility},
};

#[query_group::query_group]
pub trait DefDatabase: SourceDatabase {
    /// Computes an [`ItemTree`] for the given file or macro expansion.
    #[salsa::invoke(file_item_tree)]
    #[salsa::transparent]
    fn file_item_tree(&self, file_id: HirFileId, krate: Crate) -> &ItemTree;

    /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
    #[salsa::invoke(macro_def)]
    fn macro_def(&self, m: MacroId) -> MacroDefId;

    // region:visibilities

    #[salsa::invoke(visibility::assoc_visibility_query)]
    fn assoc_visibility(&self, def: AssocItemId) -> Visibility;

    // endregion:visibilities

    #[salsa::invoke(crate::lang_item::crate_notable_traits)]
    #[salsa::transparent]
    fn crate_notable_traits(&self, krate: Crate) -> Option<&[TraitId]>;

    #[salsa::invoke(crate_supports_no_std)]
    fn crate_supports_no_std(&self, crate_id: Crate) -> bool;

    #[salsa::invoke(include_macro_invoc)]
    fn include_macro_invoc(&self, crate_id: Crate) -> Arc<[(MacroCallId, EditionedFileId)]>;
}

/// Whether to expand procedural macros during name resolution.
///
/// Note: this struct shouldn't be exposed to ide crates -- consider using
/// [`set_expand_proc_attr_macros`] instead, if possible.
#[salsa::input(singleton, debug)]
pub(crate) struct ExpandProcAttrMacros {
    #[returns(copy)]
    pub(crate) enabled: bool,
}

pub fn set_expand_proc_attr_macros(db: &mut dyn DefDatabase, enabled: bool) {
    if let Some(expand_proc_attr_macros) = ExpandProcAttrMacros::try_get(db) {
        if expand_proc_attr_macros.enabled(db) != enabled {
            expand_proc_attr_macros.set_enabled(db).with_durability(Durability::HIGH).to(enabled);
        }
    } else {
        _ = ExpandProcAttrMacros::builder(enabled).durability(Durability::HIGH).new(db);
    }
}

// return: macro call id and include file id
fn include_macro_invoc(
    db: &dyn DefDatabase,
    krate: Crate,
) -> Arc<[(MacroCallId, EditionedFileId)]> {
    crate_def_map(db, krate)
        .modules
        .values()
        .flat_map(|m| m.scope.iter_macro_invoc())
        .filter_map(|invoc| invoc.1.loc(db).include_file_id(db, *invoc.1).map(|x| (*invoc.1, x)))
        .collect()
}

fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
    let root_module = crate_def_map(db, crate_id).root_module_id();
    let attrs = AttrFlags::query(db, AttrDefId::ModuleId(root_module));
    attrs.contains(AttrFlags::IS_NO_STD)
}

fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
    let kind = |expander, file_id, m| {
        let in_file = InFile::new(file_id, m);
        match expander {
            MacroExpander::Declarative { styles } => MacroDefKind::Declarative(in_file, styles),
            MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it),
            MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it),
            MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it),
            MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it),
            MacroExpander::UnimplementedBuiltIn => MacroDefKind::UnimplementedBuiltIn(in_file),
        }
    };

    match id {
        MacroId::Macro2Id(it) => {
            let loc = it.lookup(db);

            MacroDefId {
                krate: loc.container.krate(db),
                kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
                local_inner: false,
                allow_internal_unsafe: loc.allow_internal_unsafe,
                edition: loc.edition,
            }
        }
        MacroId::MacroRulesId(it) => {
            let loc = it.lookup(db);

            MacroDefId {
                krate: loc.container.krate(db),
                kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
                local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER),
                allow_internal_unsafe: loc
                    .flags
                    .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE),
                edition: loc.edition,
            }
        }
        MacroId::ProcMacroId(it) => {
            let loc = it.lookup(db);

            MacroDefId {
                krate: loc.container.krate(db),
                kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind),
                local_inner: false,
                allow_internal_unsafe: false,
                edition: loc.edition,
            }
        }
    }
}