hir_def/
db.rs

1//! Defines database & queries for name resolution.
2use base_db::{Crate, RootQueryDb, SourceDatabase};
3use either::Either;
4use hir_expand::{
5    EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
6    db::ExpandDatabase,
7};
8use intern::sym;
9use la_arena::ArenaMap;
10use syntax::{AstPtr, ast};
11use triomphe::Arc;
12
13use crate::{
14    AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc,
15    EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc,
16    FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc,
17    MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId,
18    ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
19    TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
20    attr::{Attrs, AttrsWithOwner},
21    expr_store::{
22        Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
23    },
24    hir::generics::GenericParams,
25    import_map::ImportMap,
26    item_tree::{ItemTree, file_item_tree_query},
27    lang_item::{self, LangItem},
28    nameres::crate_def_map,
29    signatures::{
30        ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature,
31        StructSignature, TraitSignature, TypeAliasSignature, UnionSignature,
32    },
33    tt,
34    visibility::{self, Visibility},
35};
36
37use salsa::plumbing::AsId;
38
39#[query_group::query_group(InternDatabaseStorage)]
40pub trait InternDatabase: RootQueryDb {
41    // region: items
42    #[salsa::interned]
43    fn intern_use(&self, loc: UseLoc) -> UseId;
44
45    #[salsa::interned]
46    fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId;
47
48    #[salsa::interned]
49    fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
50
51    #[salsa::interned]
52    fn intern_struct(&self, loc: StructLoc) -> StructId;
53
54    #[salsa::interned]
55    fn intern_union(&self, loc: UnionLoc) -> UnionId;
56
57    #[salsa::interned]
58    fn intern_enum(&self, loc: EnumLoc) -> EnumId;
59
60    #[salsa::interned]
61    fn intern_enum_variant(&self, loc: EnumVariantLoc) -> EnumVariantId;
62
63    #[salsa::interned]
64    fn intern_const(&self, loc: ConstLoc) -> ConstId;
65
66    #[salsa::interned]
67    fn intern_static(&self, loc: StaticLoc) -> StaticId;
68
69    #[salsa::interned]
70    fn intern_trait(&self, loc: TraitLoc) -> TraitId;
71
72    #[salsa::interned]
73    fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
74
75    #[salsa::interned]
76    fn intern_impl(&self, loc: ImplLoc) -> ImplId;
77
78    #[salsa::interned]
79    fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId;
80
81    #[salsa::interned]
82    fn intern_macro2(&self, loc: Macro2Loc) -> Macro2Id;
83
84    #[salsa::interned]
85    fn intern_proc_macro(&self, loc: ProcMacroLoc) -> ProcMacroId;
86
87    #[salsa::interned]
88    fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId;
89    // endregion: items
90
91    #[salsa::interned]
92    fn intern_block(&self, loc: BlockLoc) -> BlockId;
93}
94
95#[query_group::query_group]
96pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
97    /// Whether to expand procedural macros during name resolution.
98    #[salsa::input]
99    fn expand_proc_attr_macros(&self) -> bool;
100
101    /// Computes an [`ItemTree`] for the given file or macro expansion.
102    #[salsa::invoke(file_item_tree_query)]
103    #[salsa::transparent]
104    fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree;
105
106    /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
107    #[salsa::invoke(macro_def)]
108    fn macro_def(&self, m: MacroId) -> MacroDefId;
109
110    // region:data
111
112    #[salsa::tracked]
113    fn trait_signature(&self, trait_: TraitId) -> Arc<TraitSignature> {
114        self.trait_signature_with_source_map(trait_).0
115    }
116
117    #[salsa::tracked]
118    fn impl_signature(&self, impl_: ImplId) -> Arc<ImplSignature> {
119        self.impl_signature_with_source_map(impl_).0
120    }
121
122    #[salsa::tracked]
123    fn struct_signature(&self, struct_: StructId) -> Arc<StructSignature> {
124        self.struct_signature_with_source_map(struct_).0
125    }
126
127    #[salsa::tracked]
128    fn union_signature(&self, union_: UnionId) -> Arc<UnionSignature> {
129        self.union_signature_with_source_map(union_).0
130    }
131
132    #[salsa::tracked]
133    fn enum_signature(&self, e: EnumId) -> Arc<EnumSignature> {
134        self.enum_signature_with_source_map(e).0
135    }
136
137    #[salsa::tracked]
138    fn const_signature(&self, e: ConstId) -> Arc<ConstSignature> {
139        self.const_signature_with_source_map(e).0
140    }
141
142    #[salsa::tracked]
143    fn static_signature(&self, e: StaticId) -> Arc<StaticSignature> {
144        self.static_signature_with_source_map(e).0
145    }
146
147    #[salsa::tracked]
148    fn function_signature(&self, e: FunctionId) -> Arc<FunctionSignature> {
149        self.function_signature_with_source_map(e).0
150    }
151
152    #[salsa::tracked]
153    fn type_alias_signature(&self, e: TypeAliasId) -> Arc<TypeAliasSignature> {
154        self.type_alias_signature_with_source_map(e).0
155    }
156
157    #[salsa::invoke(TraitSignature::query)]
158    fn trait_signature_with_source_map(
159        &self,
160        trait_: TraitId,
161    ) -> (Arc<TraitSignature>, Arc<ExpressionStoreSourceMap>);
162
163    #[salsa::invoke(ImplSignature::query)]
164    fn impl_signature_with_source_map(
165        &self,
166        impl_: ImplId,
167    ) -> (Arc<ImplSignature>, Arc<ExpressionStoreSourceMap>);
168
169    #[salsa::invoke(StructSignature::query)]
170    fn struct_signature_with_source_map(
171        &self,
172        struct_: StructId,
173    ) -> (Arc<StructSignature>, Arc<ExpressionStoreSourceMap>);
174
175    #[salsa::invoke(UnionSignature::query)]
176    fn union_signature_with_source_map(
177        &self,
178        union_: UnionId,
179    ) -> (Arc<UnionSignature>, Arc<ExpressionStoreSourceMap>);
180
181    #[salsa::invoke(EnumSignature::query)]
182    fn enum_signature_with_source_map(
183        &self,
184        e: EnumId,
185    ) -> (Arc<EnumSignature>, Arc<ExpressionStoreSourceMap>);
186
187    #[salsa::invoke(ConstSignature::query)]
188    fn const_signature_with_source_map(
189        &self,
190        e: ConstId,
191    ) -> (Arc<ConstSignature>, Arc<ExpressionStoreSourceMap>);
192
193    #[salsa::invoke(StaticSignature::query)]
194    fn static_signature_with_source_map(
195        &self,
196        e: StaticId,
197    ) -> (Arc<StaticSignature>, Arc<ExpressionStoreSourceMap>);
198
199    #[salsa::invoke(FunctionSignature::query)]
200    fn function_signature_with_source_map(
201        &self,
202        e: FunctionId,
203    ) -> (Arc<FunctionSignature>, Arc<ExpressionStoreSourceMap>);
204
205    #[salsa::invoke(TypeAliasSignature::query)]
206    fn type_alias_signature_with_source_map(
207        &self,
208        e: TypeAliasId,
209    ) -> (Arc<TypeAliasSignature>, Arc<ExpressionStoreSourceMap>);
210
211    // endregion:data
212
213    #[salsa::invoke(Body::body_with_source_map_query)]
214    #[salsa::lru(512)]
215    fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);
216
217    #[salsa::invoke(Body::body_query)]
218    fn body(&self, def: DefWithBodyId) -> Arc<Body>;
219
220    #[salsa::invoke(ExprScopes::expr_scopes_query)]
221    fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
222
223    #[salsa::transparent]
224    #[salsa::invoke(GenericParams::new)]
225    fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
226
227    #[salsa::transparent]
228    #[salsa::invoke(GenericParams::generic_params_and_store)]
229    fn generic_params_and_store(
230        &self,
231        def: GenericDefId,
232    ) -> (Arc<GenericParams>, Arc<ExpressionStore>);
233
234    #[salsa::transparent]
235    #[salsa::invoke(GenericParams::generic_params_and_store_and_source_map)]
236    fn generic_params_and_store_and_source_map(
237        &self,
238        def: GenericDefId,
239    ) -> (Arc<GenericParams>, Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>);
240
241    // region:attrs
242
243    #[salsa::invoke(Attrs::fields_attrs_query)]
244    fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
245
246    // should this really be a query?
247    #[salsa::invoke(crate::attr::fields_attrs_source_map)]
248    fn fields_attrs_source_map(
249        &self,
250        def: VariantId,
251    ) -> Arc<ArenaMap<LocalFieldId, AstPtr<Either<ast::TupleField, ast::RecordField>>>>;
252
253    // FIXME: Make this a non-interned query.
254    #[salsa::invoke_interned(AttrsWithOwner::attrs_query)]
255    fn attrs(&self, def: AttrDefId) -> Attrs;
256
257    #[salsa::transparent]
258    #[salsa::invoke(lang_item::lang_attr)]
259    fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
260
261    // endregion:attrs
262
263    #[salsa::invoke(ImportMap::import_map_query)]
264    fn import_map(&self, krate: Crate) -> Arc<ImportMap>;
265
266    // region:visibilities
267
268    #[salsa::invoke(visibility::field_visibilities_query)]
269    fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
270
271    #[salsa::invoke(visibility::assoc_visibility_query)]
272    fn assoc_visibility(&self, def: AssocItemId) -> Visibility;
273
274    // endregion:visibilities
275
276    #[salsa::invoke(crate::lang_item::notable_traits_in_deps)]
277    fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>;
278    #[salsa::invoke(crate::lang_item::crate_notable_traits)]
279    fn crate_notable_traits(&self, krate: Crate) -> Option<Arc<[TraitId]>>;
280
281    #[salsa::invoke(crate_supports_no_std)]
282    fn crate_supports_no_std(&self, crate_id: Crate) -> bool;
283
284    #[salsa::invoke(include_macro_invoc)]
285    fn include_macro_invoc(&self, crate_id: Crate) -> Arc<[(MacroCallId, EditionedFileId)]>;
286}
287
288// return: macro call id and include file id
289fn include_macro_invoc(
290    db: &dyn DefDatabase,
291    krate: Crate,
292) -> Arc<[(MacroCallId, EditionedFileId)]> {
293    crate_def_map(db, krate)
294        .modules
295        .values()
296        .flat_map(|m| m.scope.iter_macro_invoc())
297        .filter_map(|invoc| {
298            db.lookup_intern_macro_call(*invoc.1)
299                .include_file_id(db, *invoc.1)
300                .map(|x| (*invoc.1, x))
301        })
302        .collect()
303}
304
305fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
306    let file = crate_id.data(db).root_file_id(db);
307    let item_tree = db.file_item_tree(file.into());
308    let attrs = item_tree.top_level_raw_attrs();
309    for attr in &**attrs {
310        match attr.path().as_ident() {
311            Some(ident) if *ident == sym::no_std => return true,
312            Some(ident) if *ident == sym::cfg_attr => {}
313            _ => continue,
314        }
315
316        // This is a `cfg_attr`; check if it could possibly expand to `no_std`.
317        // Syntax is: `#[cfg_attr(condition(cfg, style), attr0, attr1, <...>)]`
318        let tt = match attr.token_tree_value() {
319            Some(tt) => tt.token_trees(),
320            None => continue,
321        };
322
323        let segments =
324            tt.split(|tt| matches!(tt, tt::TtElement::Leaf(tt::Leaf::Punct(p)) if p.char == ','));
325        for output in segments.skip(1) {
326            match output.flat_tokens() {
327                [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::no_std => {
328                    return true;
329                }
330                _ => {}
331            }
332        }
333    }
334
335    false
336}
337
338fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
339    let kind = |expander, file_id, m| {
340        let in_file = InFile::new(file_id, m);
341        match expander {
342            MacroExpander::Declarative => MacroDefKind::Declarative(in_file),
343            MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it),
344            MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it),
345            MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it),
346            MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it),
347        }
348    };
349
350    match id {
351        MacroId::Macro2Id(it) => {
352            let loc: Macro2Loc = it.lookup(db);
353
354            MacroDefId {
355                krate: loc.container.krate,
356                kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
357                local_inner: false,
358                allow_internal_unsafe: loc.allow_internal_unsafe,
359                edition: loc.edition,
360            }
361        }
362        MacroId::MacroRulesId(it) => {
363            let loc: MacroRulesLoc = it.lookup(db);
364
365            MacroDefId {
366                krate: loc.container.krate,
367                kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
368                local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER),
369                allow_internal_unsafe: loc
370                    .flags
371                    .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE),
372                edition: loc.edition,
373            }
374        }
375        MacroId::ProcMacroId(it) => {
376            let loc = it.lookup(db);
377
378            MacroDefId {
379                krate: loc.container.krate,
380                kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind),
381                local_inner: false,
382                allow_internal_unsafe: false,
383                edition: loc.edition,
384            }
385        }
386    }
387}