cairo_lang_defs/
db.rs

1use std::collections::VecDeque;
2use std::sync::Arc;
3
4use cairo_lang_diagnostics::{DiagnosticNote, Maybe, PluginFileDiagnosticNotes, ToMaybe};
5use cairo_lang_filesystem::db::FilesGroup;
6use cairo_lang_filesystem::ids::{CrateId, Directory, FileId, FileKind, FileLongId, VirtualFile};
7use cairo_lang_parser::db::ParserGroup;
8use cairo_lang_syntax::attribute::consts::{
9    ALLOW_ATTR, ALLOW_ATTR_ATTR, DEPRECATED_ATTR, FEATURE_ATTR, FMT_SKIP_ATTR,
10    IMPLICIT_PRECEDENCE_ATTR, INLINE_ATTR, INTERNAL_ATTR, MUST_USE_ATTR, PHANTOM_ATTR,
11    STARKNET_INTERFACE_ATTR, UNSTABLE_ATTR,
12};
13use cairo_lang_syntax::attribute::structured::AttributeStructurize;
14use cairo_lang_syntax::node::ast::MaybeModuleBody;
15use cairo_lang_syntax::node::db::SyntaxGroup;
16use cairo_lang_syntax::node::element_list::ElementList;
17use cairo_lang_syntax::node::helpers::QueryAttrs;
18use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
19use cairo_lang_syntax::node::{Terminal, TypedStablePtr, TypedSyntaxNode, ast};
20use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
21use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
22use cairo_lang_utils::{Intern, LookupIntern, Upcast};
23use itertools::{Itertools, chain};
24use salsa::InternKey;
25
26use crate::ids::*;
27use crate::plugin::{DynGeneratedFileAuxData, MacroPlugin, MacroPluginMetadata, PluginDiagnostic};
28use crate::plugin_utils::try_extract_unnamed_arg;
29
30/// Salsa database interface.
31/// See [`super::ids`] for further details.
32#[salsa::query_group(DefsDatabase)]
33pub trait DefsGroup:
34    FilesGroup + SyntaxGroup + Upcast<dyn SyntaxGroup> + ParserGroup + Upcast<dyn FilesGroup>
35{
36    #[salsa::interned]
37    fn intern_constant(&self, id: ConstantLongId) -> ConstantId;
38    #[salsa::interned]
39    fn intern_submodule(&self, id: SubmoduleLongId) -> SubmoduleId;
40    #[salsa::interned]
41    fn intern_use(&self, id: UseLongId) -> UseId;
42    #[salsa::interned]
43    fn intern_global_use(&self, id: GlobalUseLongId) -> GlobalUseId;
44    #[salsa::interned]
45    fn intern_free_function(&self, id: FreeFunctionLongId) -> FreeFunctionId;
46    #[salsa::interned]
47    fn intern_impl_type_def(&self, id: ImplTypeDefLongId) -> ImplTypeDefId;
48    #[salsa::interned]
49    fn intern_impl_constant_def(&self, id: ImplConstantDefLongId) -> ImplConstantDefId;
50    #[salsa::interned]
51    fn intern_impl_impl_def(&self, id: ImplImplDefLongId) -> ImplImplDefId;
52    #[salsa::interned]
53    fn intern_impl_function(&self, id: ImplFunctionLongId) -> ImplFunctionId;
54    #[salsa::interned]
55    fn intern_struct(&self, id: StructLongId) -> StructId;
56    #[salsa::interned]
57    fn intern_enum(&self, id: EnumLongId) -> EnumId;
58    #[salsa::interned]
59    fn intern_module_type_alias(&self, id: ModuleTypeAliasLongId) -> ModuleTypeAliasId;
60    #[salsa::interned]
61    fn intern_impl_alias(&self, id: ImplAliasLongId) -> ImplAliasId;
62    #[salsa::interned]
63    fn intern_member(&self, id: MemberLongId) -> MemberId;
64    #[salsa::interned]
65    fn intern_variant(&self, id: VariantLongId) -> VariantId;
66    #[salsa::interned]
67    fn intern_trait(&self, id: TraitLongId) -> TraitId;
68    #[salsa::interned]
69    fn intern_trait_type(&self, id: TraitTypeLongId) -> TraitTypeId;
70    #[salsa::interned]
71    fn intern_trait_constant(&self, id: TraitConstantLongId) -> TraitConstantId;
72    #[salsa::interned]
73    fn intern_trait_impl(&self, id: TraitImplLongId) -> TraitImplId;
74    #[salsa::interned]
75    fn intern_trait_function(&self, id: TraitFunctionLongId) -> TraitFunctionId;
76    #[salsa::interned]
77    fn intern_impl_def(&self, id: ImplDefLongId) -> ImplDefId;
78    #[salsa::interned]
79    fn intern_extern_type(&self, id: ExternTypeLongId) -> ExternTypeId;
80    #[salsa::interned]
81    fn intern_extern_function(&self, id: ExternFunctionLongId) -> ExternFunctionId;
82    #[salsa::interned]
83    fn intern_param(&self, id: ParamLongId) -> ParamId;
84    #[salsa::interned]
85    fn intern_generic_param(&self, id: GenericParamLongId) -> GenericParamId;
86    #[salsa::interned]
87    fn intern_local_var(&self, id: LocalVarLongId) -> LocalVarId;
88    #[salsa::interned]
89    fn intern_statement_const(&self, id: StatementConstLongId) -> StatementConstId;
90    #[salsa::interned]
91    fn intern_statement_use(&self, id: StatementUseLongId) -> StatementUseId;
92    #[salsa::interned]
93    fn intern_plugin_generated_file(&self, id: PluginGeneratedFileLongId) -> PluginGeneratedFileId;
94
95    // Plugins.
96    // ========
97
98    #[salsa::input]
99    fn default_macro_plugins(&self) -> Arc<[MacroPluginId]>;
100
101    #[salsa::input]
102    fn macro_plugin_overrides(&self) -> Arc<OrderedHashMap<CrateId, Arc<[MacroPluginId]>>>;
103
104    #[salsa::interned]
105    fn intern_macro_plugin(&self, plugin: MacroPluginLongId) -> MacroPluginId;
106
107    /// Returns [`MacroPluginId`]s of the plugins set for the crate with [`CrateId`].
108    /// Provides an override if it has been set with
109    /// [`DefsGroupEx::set_override_crate_macro_plugins`] or the default
110    /// ([`DefsGroup::default_macro_plugins`]) otherwise.
111    fn crate_macro_plugins(&self, crate_id: CrateId) -> Arc<[MacroPluginId]>;
112
113    #[salsa::input]
114    fn default_inline_macro_plugins(&self) -> Arc<OrderedHashMap<String, InlineMacroExprPluginId>>;
115
116    #[salsa::input]
117    fn inline_macro_plugin_overrides(
118        &self,
119    ) -> Arc<OrderedHashMap<CrateId, Arc<OrderedHashMap<String, InlineMacroExprPluginId>>>>;
120
121    #[salsa::interned]
122    fn intern_inline_macro_plugin(
123        &self,
124        plugin: InlineMacroExprPluginLongId,
125    ) -> InlineMacroExprPluginId;
126
127    /// Returns [`InlineMacroExprPluginId`]s of the plugins set for the crate with [`CrateId`].
128    /// Provides an override if it has been set with
129    /// [`DefsGroupEx::set_override_crate_inline_macro_plugins`] or the default
130    /// ([`DefsGroup::default_inline_macro_plugins`]) otherwise.
131    fn crate_inline_macro_plugins(
132        &self,
133        crate_id: CrateId,
134    ) -> Arc<OrderedHashMap<String, InlineMacroExprPluginId>>;
135
136    /// Returns the set of attributes allowed anywhere.
137    /// An attribute on any item that is not in this set will be handled as an unknown attribute.
138    fn allowed_attributes(&self, crate_id: CrateId) -> Arc<OrderedHashSet<String>>;
139
140    /// Returns the set of attributes allowed on statements.
141    /// An attribute on a statement that is not in this set will be handled as an unknown attribute.
142    fn allowed_statement_attributes(&self) -> Arc<OrderedHashSet<String>>;
143
144    /// Returns the set of `derive` that were declared as by a plugin.
145    /// A derive that is not in this set will be handled as an unknown derive.
146    fn declared_derives(&self, crate_id: CrateId) -> Arc<OrderedHashSet<String>>;
147
148    /// Returns the set of attributes that were declared as phantom type attributes by a plugin,
149    /// i.e. a type marked with this attribute is considered a phantom type.
150    fn declared_phantom_type_attributes(&self, crate_id: CrateId) -> Arc<OrderedHashSet<String>>;
151
152    /// Checks whether the submodule is defined as inline.
153    fn is_submodule_inline(&self, submodule_id: SubmoduleId) -> Maybe<bool>;
154
155    // Module to syntax.
156    /// Gets the main file of the module.
157    /// A module might have more virtual files generated by plugins.
158    fn module_main_file(&self, module_id: ModuleId) -> Maybe<FileId>;
159    /// Gets all the files of a module - main files and generated virtual files.
160    fn module_files(&self, module_id: ModuleId) -> Maybe<Arc<[FileId]>>;
161    /// Gets a file from a module and a FileIndex (i.e. ModuleFileId).
162    fn module_file(&self, module_id: ModuleFileId) -> Maybe<FileId>;
163    /// Gets the directory of a module.
164    fn module_dir(&self, module_id: ModuleId) -> Maybe<Directory>;
165
166    // File to module.
167    fn crate_modules(&self, crate_id: CrateId) -> Arc<[ModuleId]>;
168    fn priv_file_to_module_mapping(&self) -> Arc<OrderedHashMap<FileId, Vec<ModuleId>>>;
169    fn file_modules(&self, file_id: FileId) -> Maybe<Arc<[ModuleId]>>;
170
171    // Module level resolving.
172    fn priv_module_data(&self, module_id: ModuleId) -> Maybe<ModuleData>;
173    // Returns the information about sub-files generated by the file in the module.
174    fn priv_module_sub_files(
175        &self,
176        module_id: ModuleId,
177        file_id: FileId,
178    ) -> Maybe<Arc<PrivModuleSubFiles>>;
179    fn module_submodules(
180        &self,
181        module_id: ModuleId,
182    ) -> Maybe<Arc<OrderedHashMap<SubmoduleId, ast::ItemModule>>>;
183    fn module_submodules_ids(&self, module_id: ModuleId) -> Maybe<Arc<[SubmoduleId]>>;
184    fn module_constants(
185        &self,
186        module_id: ModuleId,
187    ) -> Maybe<Arc<OrderedHashMap<ConstantId, ast::ItemConstant>>>;
188    fn module_constants_ids(&self, module_id: ModuleId) -> Maybe<Arc<[ConstantId]>>;
189    fn module_constant_by_id(&self, constant_id: ConstantId) -> Maybe<Option<ast::ItemConstant>>;
190    fn module_free_functions(
191        &self,
192        module_id: ModuleId,
193    ) -> Maybe<Arc<OrderedHashMap<FreeFunctionId, ast::FunctionWithBody>>>;
194    fn module_free_functions_ids(&self, module_id: ModuleId) -> Maybe<Arc<[FreeFunctionId]>>;
195    fn module_free_function_by_id(
196        &self,
197        free_function_id: FreeFunctionId,
198    ) -> Maybe<Option<ast::FunctionWithBody>>;
199    fn module_items(&self, module_id: ModuleId) -> Maybe<Arc<[ModuleItemId]>>;
200    fn module_global_uses(
201        &self,
202        module_id: ModuleId,
203    ) -> Maybe<Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>>;
204    /// Returns the stable ptr of the name of a module item.
205    fn module_item_name_stable_ptr(
206        &self,
207        module_id: ModuleId,
208        item_id: ModuleItemId,
209    ) -> Maybe<SyntaxStablePtrId>;
210    fn module_uses(
211        &self,
212        module_id: ModuleId,
213    ) -> Maybe<Arc<OrderedHashMap<UseId, ast::UsePathLeaf>>>;
214    fn module_uses_ids(&self, module_id: ModuleId) -> Maybe<Arc<[UseId]>>;
215    fn module_use_by_id(&self, use_id: UseId) -> Maybe<Option<ast::UsePathLeaf>>;
216    fn module_global_use_by_id(
217        &self,
218        global_use_id: GlobalUseId,
219    ) -> Maybe<Option<ast::UsePathStar>>;
220    fn module_structs(
221        &self,
222        module_id: ModuleId,
223    ) -> Maybe<Arc<OrderedHashMap<StructId, ast::ItemStruct>>>;
224    fn module_structs_ids(&self, module_id: ModuleId) -> Maybe<Arc<[StructId]>>;
225    fn module_struct_by_id(&self, struct_id: StructId) -> Maybe<Option<ast::ItemStruct>>;
226    fn module_enums(
227        &self,
228        module_id: ModuleId,
229    ) -> Maybe<Arc<OrderedHashMap<EnumId, ast::ItemEnum>>>;
230    fn module_enums_ids(&self, module_id: ModuleId) -> Maybe<Arc<[EnumId]>>;
231    fn module_enum_by_id(&self, enum_id: EnumId) -> Maybe<Option<ast::ItemEnum>>;
232    fn module_type_aliases(
233        &self,
234        module_id: ModuleId,
235    ) -> Maybe<Arc<OrderedHashMap<ModuleTypeAliasId, ast::ItemTypeAlias>>>;
236    fn module_type_aliases_ids(&self, module_id: ModuleId) -> Maybe<Arc<[ModuleTypeAliasId]>>;
237    fn module_type_alias_by_id(
238        &self,
239        module_type_alias_id: ModuleTypeAliasId,
240    ) -> Maybe<Option<ast::ItemTypeAlias>>;
241    fn module_impl_aliases(
242        &self,
243        module_id: ModuleId,
244    ) -> Maybe<Arc<OrderedHashMap<ImplAliasId, ast::ItemImplAlias>>>;
245    fn module_impl_aliases_ids(&self, module_id: ModuleId) -> Maybe<Arc<[ImplAliasId]>>;
246    fn module_impl_alias_by_id(
247        &self,
248        impl_alias_id: ImplAliasId,
249    ) -> Maybe<Option<ast::ItemImplAlias>>;
250    fn module_traits(
251        &self,
252        module_id: ModuleId,
253    ) -> Maybe<Arc<OrderedHashMap<TraitId, ast::ItemTrait>>>;
254    fn module_traits_ids(&self, module_id: ModuleId) -> Maybe<Arc<[TraitId]>>;
255    fn module_trait_by_id(&self, trait_id: TraitId) -> Maybe<Option<ast::ItemTrait>>;
256    fn module_impls(
257        &self,
258        module_id: ModuleId,
259    ) -> Maybe<Arc<OrderedHashMap<ImplDefId, ast::ItemImpl>>>;
260    fn module_impls_ids(&self, module_id: ModuleId) -> Maybe<Arc<[ImplDefId]>>;
261    fn module_impl_by_id(&self, impl_id: ImplDefId) -> Maybe<Option<ast::ItemImpl>>;
262    fn module_extern_types(
263        &self,
264        module_id: ModuleId,
265    ) -> Maybe<Arc<OrderedHashMap<ExternTypeId, ast::ItemExternType>>>;
266    fn module_extern_types_ids(&self, module_id: ModuleId) -> Maybe<Arc<[ExternTypeId]>>;
267    fn module_extern_type_by_id(
268        &self,
269        extern_type_id: ExternTypeId,
270    ) -> Maybe<Option<ast::ItemExternType>>;
271    fn module_extern_functions(
272        &self,
273        module_id: ModuleId,
274    ) -> Maybe<Arc<OrderedHashMap<ExternFunctionId, ast::ItemExternFunction>>>;
275    fn module_extern_functions_ids(&self, module_id: ModuleId) -> Maybe<Arc<[ExternFunctionId]>>;
276    fn module_extern_function_by_id(
277        &self,
278        extern_function_id: ExternFunctionId,
279    ) -> Maybe<Option<ast::ItemExternFunction>>;
280    fn module_ancestors(&self, module_id: ModuleId) -> OrderedHashSet<ModuleId>;
281    fn module_generated_file_aux_data(
282        &self,
283        module_id: ModuleId,
284    ) -> Maybe<Arc<[Option<DynGeneratedFileAuxData>]>>;
285    fn module_plugin_diagnostics(
286        &self,
287        module_id: ModuleId,
288    ) -> Maybe<Arc<[(ModuleFileId, PluginDiagnostic)]>>;
289    /// Diagnostic notes for diagnostics originating in the plugin generated files identified by
290    /// [`FileId`].
291    fn module_plugin_diagnostics_notes(
292        &self,
293        module_id: ModuleId,
294    ) -> Maybe<Arc<PluginFileDiagnosticNotes>>;
295}
296
297/// Initializes the [`DefsGroup`] database to a proper state.
298pub fn init_defs_group(db: &mut dyn DefsGroup) {
299    db.set_macro_plugin_overrides(Arc::new(OrderedHashMap::default()));
300    db.set_inline_macro_plugin_overrides(Arc::new(OrderedHashMap::default()));
301}
302
303fn crate_macro_plugins(db: &dyn DefsGroup, crate_id: CrateId) -> Arc<[MacroPluginId]> {
304    db.macro_plugin_overrides()
305        .get(&crate_id)
306        .cloned()
307        .unwrap_or_else(|| db.default_macro_plugins())
308}
309
310fn crate_inline_macro_plugins(
311    db: &dyn DefsGroup,
312    crate_id: CrateId,
313) -> Arc<OrderedHashMap<String, InlineMacroExprPluginId>> {
314    db.inline_macro_plugin_overrides()
315        .get(&crate_id)
316        .cloned()
317        .unwrap_or_else(|| db.default_inline_macro_plugins())
318}
319
320fn allowed_attributes(db: &dyn DefsGroup, crate_id: CrateId) -> Arc<OrderedHashSet<String>> {
321    let base_attrs = [
322        INLINE_ATTR,
323        MUST_USE_ATTR,
324        UNSTABLE_ATTR,
325        DEPRECATED_ATTR,
326        INTERNAL_ATTR,
327        ALLOW_ATTR,
328        ALLOW_ATTR_ATTR,
329        FEATURE_ATTR,
330        PHANTOM_ATTR,
331        IMPLICIT_PRECEDENCE_ATTR,
332        FMT_SKIP_ATTR,
333        // TODO(orizi): Remove this once `starknet` is removed from corelib.
334        STARKNET_INTERFACE_ATTR,
335    ];
336
337    let crate_plugins = db.crate_macro_plugins(crate_id);
338
339    Arc::new(OrderedHashSet::from_iter(chain!(
340        base_attrs.map(|attr| attr.into()),
341        crate_plugins
342            .iter()
343            .flat_map(|plugin| db.lookup_intern_macro_plugin(*plugin).declared_attributes())
344    )))
345}
346
347fn allowed_statement_attributes(_db: &dyn DefsGroup) -> Arc<OrderedHashSet<String>> {
348    let all_attributes = [FMT_SKIP_ATTR, ALLOW_ATTR, FEATURE_ATTR];
349    Arc::new(OrderedHashSet::from_iter(all_attributes.map(|attr| attr.into())))
350}
351
352fn declared_derives(db: &dyn DefsGroup, crate_id: CrateId) -> Arc<OrderedHashSet<String>> {
353    Arc::new(OrderedHashSet::from_iter(
354        db.crate_macro_plugins(crate_id)
355            .iter()
356            .flat_map(|plugin| db.lookup_intern_macro_plugin(*plugin).declared_derives()),
357    ))
358}
359
360fn declared_phantom_type_attributes(
361    db: &dyn DefsGroup,
362    crate_id: CrateId,
363) -> Arc<OrderedHashSet<String>> {
364    let crate_plugins = db.crate_macro_plugins(crate_id);
365
366    Arc::new(OrderedHashSet::from_iter(chain!(
367        [PHANTOM_ATTR.into()],
368        crate_plugins
369            .iter()
370            .flat_map(|plugin| db.lookup_intern_macro_plugin(*plugin).phantom_type_attributes())
371    )))
372}
373
374fn is_submodule_inline(db: &dyn DefsGroup, submodule_id: SubmoduleId) -> Maybe<bool> {
375    let parent = submodule_id.parent_module(db);
376    let item_module_ast = &db.priv_module_data(parent)?.submodules[&submodule_id];
377    match item_module_ast.body(db.upcast()) {
378        MaybeModuleBody::Some(_) => Ok(true),
379        MaybeModuleBody::None(_) => Ok(false),
380    }
381}
382
383fn module_main_file(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<FileId> {
384    Ok(match module_id {
385        ModuleId::CrateRoot(crate_id) => {
386            db.crate_config(crate_id).to_maybe()?.root.file(db.upcast(), "lib.cairo".into())
387        }
388        ModuleId::Submodule(submodule_id) => {
389            let parent = submodule_id.parent_module(db);
390            if db.is_submodule_inline(submodule_id)? {
391                // This is an inline module, we return the file where the inline module was
392                // defined. It can be either the file of the parent module
393                // or a plugin-generated virtual file.
394                db.module_file(submodule_id.module_file_id(db))?
395            } else {
396                let name = submodule_id.name(db);
397                db.module_dir(parent)?.file(db.upcast(), format!("{name}.cairo").into())
398            }
399        }
400    })
401}
402
403fn module_files(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[FileId]>> {
404    Ok(db.priv_module_data(module_id)?.files.into())
405}
406
407fn module_file(db: &dyn DefsGroup, module_file_id: ModuleFileId) -> Maybe<FileId> {
408    Ok(db.module_files(module_file_id.0)?[module_file_id.1.0])
409}
410
411fn module_dir(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Directory> {
412    match module_id {
413        ModuleId::CrateRoot(crate_id) => {
414            db.crate_config(crate_id).to_maybe().map(|config| config.root)
415        }
416        ModuleId::Submodule(submodule_id) => {
417            let parent = submodule_id.parent_module(db);
418            let name = submodule_id.name(db);
419            Ok(db.module_dir(parent)?.subdir(name))
420        }
421    }
422}
423
424/// Appends all the modules under the given module, including nested modules.
425fn collect_modules_under(db: &dyn DefsGroup, modules: &mut Vec<ModuleId>, module_id: ModuleId) {
426    modules.push(module_id);
427    if let Ok(submodule_ids) = db.module_submodules_ids(module_id) {
428        for submodule_module_id in submodule_ids.iter().copied() {
429            collect_modules_under(db, modules, ModuleId::Submodule(submodule_module_id));
430        }
431    }
432}
433
434/// Returns all the modules in the crate, including recursively.
435fn crate_modules(db: &dyn DefsGroup, crate_id: CrateId) -> Arc<[ModuleId]> {
436    let mut modules = Vec::new();
437    collect_modules_under(db, &mut modules, ModuleId::CrateRoot(crate_id));
438    modules.into()
439}
440
441fn priv_file_to_module_mapping(db: &dyn DefsGroup) -> Arc<OrderedHashMap<FileId, Vec<ModuleId>>> {
442    let mut mapping = OrderedHashMap::<FileId, Vec<ModuleId>>::default();
443    for crate_id in db.crates() {
444        for module_id in db.crate_modules(crate_id).iter().copied() {
445            if let Ok(files) = db.module_files(module_id) {
446                for file_id in files.iter().copied() {
447                    match mapping.get_mut(&file_id) {
448                        Some(file_modules) => {
449                            file_modules.push(module_id);
450                        }
451                        None => {
452                            mapping.insert(file_id, vec![module_id]);
453                        }
454                    }
455                }
456            }
457        }
458    }
459    mapping.into()
460}
461fn file_modules(db: &dyn DefsGroup, file_id: FileId) -> Maybe<Arc<[ModuleId]>> {
462    Ok(db.priv_file_to_module_mapping().get(&file_id).to_maybe()?.clone().into())
463}
464
465#[derive(Clone, Debug, PartialEq, Eq)]
466pub struct ModuleData {
467    /// The list of IDs of all items in the module. Each ID here is guaranteed to be a key in one
468    /// of the specific-item-kind maps.
469    items: Arc<[ModuleItemId]>,
470
471    // Specific-item-kind maps
472    constants: Arc<OrderedHashMap<ConstantId, ast::ItemConstant>>,
473    submodules: Arc<OrderedHashMap<SubmoduleId, ast::ItemModule>>,
474    uses: Arc<OrderedHashMap<UseId, ast::UsePathLeaf>>,
475    free_functions: Arc<OrderedHashMap<FreeFunctionId, ast::FunctionWithBody>>,
476    structs: Arc<OrderedHashMap<StructId, ast::ItemStruct>>,
477    enums: Arc<OrderedHashMap<EnumId, ast::ItemEnum>>,
478    type_aliases: Arc<OrderedHashMap<ModuleTypeAliasId, ast::ItemTypeAlias>>,
479    impl_aliases: Arc<OrderedHashMap<ImplAliasId, ast::ItemImplAlias>>,
480    traits: Arc<OrderedHashMap<TraitId, ast::ItemTrait>>,
481    impls: Arc<OrderedHashMap<ImplDefId, ast::ItemImpl>>,
482    extern_types: Arc<OrderedHashMap<ExternTypeId, ast::ItemExternType>>,
483    extern_functions: Arc<OrderedHashMap<ExternFunctionId, ast::ItemExternFunction>>,
484    global_uses: Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>,
485
486    files: Vec<FileId>,
487    /// Generation info for each file. Virtual files have Some. Other files have None.
488    generated_file_aux_data: Vec<Option<DynGeneratedFileAuxData>>,
489    plugin_diagnostics: Vec<(ModuleFileId, PluginDiagnostic)>,
490    /// Diagnostic notes for diagnostics originating in the plugin generated files identified by
491    /// [`FileId`].
492    /// Diagnostic notes are added with `note: ` prefix at the end of diagnostic display.
493    diagnostics_notes: PluginFileDiagnosticNotes,
494}
495
496/// Information about generated files from running on a module file.
497#[derive(Clone, Debug, Eq, PartialEq)]
498pub struct PrivModuleSubFiles {
499    /// The files generated by plugins running on items.
500    files: OrderedHashMap<FileId, VirtualFile>,
501    /// The aux data per such file.
502    aux_data: Vec<Option<DynGeneratedFileAuxData>>,
503    /// The items not filtered out by plugins.
504    items: Vec<ast::ModuleItem>,
505    /// The diagnostics generated by the plugins.
506    plugin_diagnostics: Vec<PluginDiagnostic>,
507    /// Diagnostic notes for diagnostics originating in the plugin generated files identified by
508    /// [`FileId`].
509    /// Diagnostic notes are added with `note: ` prefix at the end of diagnostic display.
510    diagnostics_notes: PluginFileDiagnosticNotes,
511}
512
513fn priv_module_data(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<ModuleData> {
514    let syntax_db = db.upcast();
515    let module_file = db.module_main_file(module_id)?;
516    let main_file_aux_data = if let ModuleId::Submodule(submodule_id) = module_id {
517        let parent_module_data = db.priv_module_data(submodule_id.parent_module(db))?;
518        let item_module_ast = &parent_module_data.submodules[&submodule_id];
519        if matches!(item_module_ast.body(syntax_db), MaybeModuleBody::Some(_)) {
520            // TODO(spapini): Diagnostics in this module that get mapped to parent module
521            // should lie in that modules ModuleData, or somehow collected by its
522            // diagnostics collector function.
523
524            // If this is an inline module, copy its generation file info from the parent
525            // module, from the file where this submodule was defined.
526            parent_module_data
527                .generated_file_aux_data
528                .into_iter()
529                .nth(submodule_id.file_index(db).0)
530                .unwrap()
531        } else {
532            None
533        }
534    } else {
535        None
536    };
537    let mut file_queue = VecDeque::new();
538    file_queue.push_back(module_file);
539    let mut constants = OrderedHashMap::default();
540    let mut submodules = OrderedHashMap::default();
541    let mut uses = OrderedHashMap::default();
542    let mut free_functions = OrderedHashMap::default();
543    let mut structs = OrderedHashMap::default();
544    let mut enums = OrderedHashMap::default();
545    let mut type_aliases = OrderedHashMap::default();
546    let mut impl_aliases = OrderedHashMap::default();
547    let mut traits = OrderedHashMap::default();
548    let mut impls = OrderedHashMap::default();
549    let mut extern_types = OrderedHashMap::default();
550    let mut extern_functions = OrderedHashMap::default();
551    let mut global_uses = OrderedHashMap::default();
552    let mut aux_data = Vec::new();
553    let mut files = Vec::new();
554    let mut plugin_diagnostics = Vec::new();
555    let mut diagnostics_notes = OrderedHashMap::default();
556
557    let mut items = vec![];
558    aux_data.push(main_file_aux_data);
559    while let Some(file_id) = file_queue.pop_front() {
560        let file_index = FileIndex(files.len());
561        let module_file_id = ModuleFileId(module_id, file_index);
562        files.push(file_id);
563
564        let priv_module_data = db.priv_module_sub_files(module_id, file_id)?;
565        diagnostics_notes.extend(priv_module_data.diagnostics_notes.clone().into_iter());
566        file_queue.extend(priv_module_data.files.keys().copied());
567        for diag in &priv_module_data.plugin_diagnostics {
568            plugin_diagnostics.push((module_file_id, diag.clone()));
569        }
570        aux_data.extend(priv_module_data.aux_data.iter().cloned());
571        for item_ast in &priv_module_data.items {
572            match item_ast.clone() {
573                ast::ModuleItem::Constant(constant) => {
574                    let item_id = ConstantLongId(module_file_id, constant.stable_ptr()).intern(db);
575                    constants.insert(item_id, constant);
576                    items.push(ModuleItemId::Constant(item_id));
577                }
578                ast::ModuleItem::Module(module) => {
579                    let item_id = SubmoduleLongId(module_file_id, module.stable_ptr()).intern(db);
580                    submodules.insert(item_id, module);
581                    items.push(ModuleItemId::Submodule(item_id));
582                }
583                ast::ModuleItem::Use(us) => {
584                    for leaf in get_all_path_leaves(db.upcast(), &us) {
585                        let id = UseLongId(module_file_id, leaf.stable_ptr()).intern(db);
586                        uses.insert(id, leaf);
587                        items.push(ModuleItemId::Use(id));
588                    }
589                    for star in get_all_path_stars(db.upcast(), &us) {
590                        let id = GlobalUseLongId(module_file_id, star.stable_ptr()).intern(db);
591                        global_uses.insert(id, star);
592                    }
593                }
594                ast::ModuleItem::FreeFunction(function) => {
595                    let item_id =
596                        FreeFunctionLongId(module_file_id, function.stable_ptr()).intern(db);
597                    free_functions.insert(item_id, function);
598                    items.push(ModuleItemId::FreeFunction(item_id));
599                }
600                ast::ModuleItem::ExternFunction(extern_function) => {
601                    let item_id =
602                        ExternFunctionLongId(module_file_id, extern_function.stable_ptr())
603                            .intern(db);
604                    extern_functions.insert(item_id, extern_function);
605                    items.push(ModuleItemId::ExternFunction(item_id));
606                }
607                ast::ModuleItem::ExternType(extern_type) => {
608                    let item_id =
609                        ExternTypeLongId(module_file_id, extern_type.stable_ptr()).intern(db);
610                    extern_types.insert(item_id, extern_type);
611                    items.push(ModuleItemId::ExternType(item_id));
612                }
613                ast::ModuleItem::Trait(trt) => {
614                    let item_id = TraitLongId(module_file_id, trt.stable_ptr()).intern(db);
615                    traits.insert(item_id, trt);
616                    items.push(ModuleItemId::Trait(item_id));
617                }
618                ast::ModuleItem::Impl(imp) => {
619                    let item_id = ImplDefLongId(module_file_id, imp.stable_ptr()).intern(db);
620                    impls.insert(item_id, imp);
621                    items.push(ModuleItemId::Impl(item_id));
622                }
623                ast::ModuleItem::Struct(structure) => {
624                    let item_id = StructLongId(module_file_id, structure.stable_ptr()).intern(db);
625                    structs.insert(item_id, structure);
626                    items.push(ModuleItemId::Struct(item_id));
627                }
628                ast::ModuleItem::Enum(enm) => {
629                    let item_id = EnumLongId(module_file_id, enm.stable_ptr()).intern(db);
630                    enums.insert(item_id, enm);
631                    items.push(ModuleItemId::Enum(item_id));
632                }
633                ast::ModuleItem::TypeAlias(type_alias) => {
634                    let item_id =
635                        ModuleTypeAliasLongId(module_file_id, type_alias.stable_ptr()).intern(db);
636                    type_aliases.insert(item_id, type_alias);
637                    items.push(ModuleItemId::TypeAlias(item_id));
638                }
639                ast::ModuleItem::ImplAlias(impl_alias) => {
640                    let item_id =
641                        ImplAliasLongId(module_file_id, impl_alias.stable_ptr()).intern(db);
642                    impl_aliases.insert(item_id, impl_alias);
643                    items.push(ModuleItemId::ImplAlias(item_id));
644                }
645                ast::ModuleItem::InlineMacro(inline_macro_ast) => plugin_diagnostics.push((
646                    module_file_id,
647                    PluginDiagnostic::error(
648                        &inline_macro_ast,
649                        format!(
650                            "Unknown inline item macro: '{}'.",
651                            inline_macro_ast.name(db.upcast()).text(db.upcast())
652                        ),
653                    ),
654                )),
655                ast::ModuleItem::HeaderDoc(_) => {}
656                ast::ModuleItem::Missing(_) => {}
657            }
658        }
659    }
660    let res = ModuleData {
661        items: items.into(),
662        constants: constants.into(),
663        submodules: submodules.into(),
664        uses: uses.into(),
665        free_functions: free_functions.into(),
666        structs: structs.into(),
667        enums: enums.into(),
668        type_aliases: type_aliases.into(),
669        impl_aliases: impl_aliases.into(),
670        traits: traits.into(),
671        impls: impls.into(),
672        extern_types: extern_types.into(),
673        extern_functions: extern_functions.into(),
674        global_uses: global_uses.into(),
675        files,
676        generated_file_aux_data: aux_data,
677        plugin_diagnostics,
678        diagnostics_notes,
679    };
680    Ok(res)
681}
682
683/// Returns the `VirtualFile` matching the given external id.
684pub fn try_ext_as_virtual_impl(
685    db: &dyn DefsGroup,
686    external_id: salsa::InternId,
687) -> Option<VirtualFile> {
688    let long_id = PluginGeneratedFileId::from_intern_id(external_id).lookup_intern(db);
689    let file_id = FileLongId::External(external_id).intern(db);
690    let data = db
691        .priv_module_sub_files(long_id.module_id, long_id.stable_ptr.file_id(db.upcast()))
692        .unwrap();
693    data.files.get(&file_id).cloned()
694}
695
696fn priv_module_sub_files(
697    db: &dyn DefsGroup,
698    module_id: ModuleId,
699    file_id: FileId,
700) -> Maybe<Arc<PrivModuleSubFiles>> {
701    let syntax_db = db.upcast();
702    let module_main_file = db.module_main_file(module_id)?;
703    let file_syntax = db.file_module_syntax(file_id)?;
704    let item_asts = if module_main_file == file_id {
705        if let ModuleId::Submodule(submodule_id) = module_id {
706            let data = db.priv_module_data(submodule_id.parent_module(db))?;
707            if let MaybeModuleBody::Some(body) = data.submodules[&submodule_id].body(db.upcast()) {
708                Some(body.items(syntax_db))
709            } else {
710                None
711            }
712        } else {
713            None
714        }
715    } else {
716        None
717    }
718    .unwrap_or_else(|| file_syntax.items(syntax_db));
719
720    let crate_id = module_id.owning_crate(db);
721
722    let allowed_attributes = db.allowed_attributes(crate_id);
723    // TODO(orizi): Actually extract the allowed features per module.
724    let allowed_features = Default::default();
725
726    let cfg_set = db
727        .crate_config(crate_id)
728        .and_then(|cfg| cfg.settings.cfg_set.map(Arc::new))
729        .unwrap_or(db.cfg_set());
730    let edition = db
731        .crate_config(module_id.owning_crate(db))
732        .map(|cfg| cfg.settings.edition)
733        .unwrap_or_default();
734    let metadata = MacroPluginMetadata {
735        cfg_set: &cfg_set,
736        declared_derives: &db.declared_derives(crate_id),
737        allowed_features: &allowed_features,
738        edition,
739    };
740
741    let mut files = OrderedHashMap::<_, _>::default();
742    let mut aux_data = Vec::new();
743    let mut items = Vec::new();
744    let mut plugin_diagnostics = Vec::new();
745    let mut diagnostics_notes = OrderedHashMap::default();
746    for item_ast in item_asts.elements(syntax_db) {
747        let mut remove_original_item = false;
748        // Iterate the plugins by their order. The first one to change something (either
749        // generate new code, remove the original code, or both), breaks the loop. If more
750        // plugins might have act on the item, they can do it on the generated code.
751        for plugin_id in db.crate_macro_plugins(crate_id).iter() {
752            let plugin = db.lookup_intern_macro_plugin(*plugin_id);
753
754            let result = plugin.generate_code(db.upcast(), item_ast.clone(), &metadata);
755            plugin_diagnostics.extend(result.diagnostics);
756            if result.remove_original_item {
757                remove_original_item = true;
758            }
759
760            if let Some(generated) = result.code {
761                let generated_file_id = FileLongId::External(
762                    PluginGeneratedFileLongId {
763                        module_id,
764                        stable_ptr: item_ast.stable_ptr().untyped(),
765                        name: generated.name.clone(),
766                    }
767                    .intern(db)
768                    .as_intern_id(),
769                )
770                .intern(db);
771                if let Some(text) = generated.diagnostics_note {
772                    diagnostics_notes
773                        .insert(generated_file_id, DiagnosticNote { text, location: None });
774                }
775                files.insert(
776                    generated_file_id,
777                    VirtualFile {
778                        parent: Some(file_id),
779                        name: generated.name,
780                        content: generated.content.into(),
781                        code_mappings: generated.code_mappings.into(),
782                        kind: FileKind::Module,
783                    },
784                );
785                aux_data.push(generated.aux_data);
786            }
787            if remove_original_item {
788                break;
789            }
790        }
791        if remove_original_item {
792            // Don't add the original item to the module data.
793            continue;
794        }
795        validate_attributes(syntax_db, &allowed_attributes, &item_ast, &mut plugin_diagnostics);
796        items.push(item_ast);
797    }
798    let res = PrivModuleSubFiles { files, aux_data, items, plugin_diagnostics, diagnostics_notes };
799    Ok(res.into())
800}
801
802/// Collects attributes allowed by `allow_attr` attribute.
803fn collect_extra_allowed_attributes(
804    db: &dyn SyntaxGroup,
805    item: &impl QueryAttrs,
806    plugin_diagnostics: &mut Vec<PluginDiagnostic>,
807) -> OrderedHashSet<String> {
808    let mut extra_allowed_attributes = OrderedHashSet::default();
809    for attr in item.attributes_elements(db) {
810        if attr.attr(db).as_syntax_node().get_text_without_trivia(db) == ALLOW_ATTR_ATTR {
811            let args = attr.clone().structurize(db).args;
812            if args.is_empty() {
813                plugin_diagnostics.push(PluginDiagnostic::error(
814                    attr.stable_ptr(),
815                    "Expected arguments.".to_string(),
816                ));
817                continue;
818            }
819            for arg in args {
820                if let Some(ast::Expr::Path(path)) = try_extract_unnamed_arg(db, &arg.arg) {
821                    if let [ast::PathSegment::Simple(segment)] = &path.elements(db)[..] {
822                        extra_allowed_attributes.insert(segment.ident(db).text(db).into());
823                        continue;
824                    }
825                }
826                plugin_diagnostics.push(PluginDiagnostic::error(
827                    &arg.arg,
828                    "Expected simple identifier.".to_string(),
829                ));
830            }
831        }
832    }
833    extra_allowed_attributes
834}
835
836/// Validates that all attributes on the given item are in the allowed set or adds diagnostics.
837pub fn validate_attributes_flat(
838    db: &dyn SyntaxGroup,
839    allowed_attributes: &OrderedHashSet<String>,
840    extra_allowed_attributes: &OrderedHashSet<String>,
841    item: &impl QueryAttrs,
842    plugin_diagnostics: &mut Vec<PluginDiagnostic>,
843) {
844    let local_extra_attributes = collect_extra_allowed_attributes(db, item, plugin_diagnostics);
845    for attr in item.attributes_elements(db) {
846        let attr_text = attr.attr(db).as_syntax_node().get_text_without_trivia(db);
847        if !(allowed_attributes.contains(&attr_text)
848            || extra_allowed_attributes.contains(&attr_text)
849            || local_extra_attributes.contains(&attr_text))
850        {
851            plugin_diagnostics
852                .push(PluginDiagnostic::error(&attr, "Unsupported attribute.".to_string()));
853        }
854    }
855}
856
857/// Validates that all attributes on all items in the given element list are in the allowed set or
858/// adds diagnostics.
859fn validate_attributes_element_list<Item: QueryAttrs + TypedSyntaxNode, const STEP: usize>(
860    db: &dyn SyntaxGroup,
861    allowed_attributes: &OrderedHashSet<String>,
862    extra_allowed_attributes: &OrderedHashSet<String>,
863    items: &ElementList<Item, STEP>,
864    plugin_diagnostics: &mut Vec<PluginDiagnostic>,
865) {
866    for item in items.elements(db) {
867        validate_attributes_flat(
868            db,
869            allowed_attributes,
870            extra_allowed_attributes,
871            &item,
872            plugin_diagnostics,
873        );
874    }
875}
876
877/// Validates that all attributes on an item and on items contained within it are in the allowed set
878/// or adds diagnostics.
879fn validate_attributes(
880    db: &dyn SyntaxGroup,
881    allowed_attributes: &OrderedHashSet<String>,
882    item_ast: &ast::ModuleItem,
883    plugin_diagnostics: &mut Vec<PluginDiagnostic>,
884) {
885    let extra_allowed_attributes =
886        collect_extra_allowed_attributes(db, item_ast, plugin_diagnostics);
887    validate_attributes_flat(
888        db,
889        allowed_attributes,
890        &extra_allowed_attributes,
891        item_ast,
892        plugin_diagnostics,
893    );
894
895    match item_ast {
896        ast::ModuleItem::Trait(item) => {
897            if let ast::MaybeTraitBody::Some(body) = item.body(db) {
898                validate_attributes_element_list(
899                    db,
900                    allowed_attributes,
901                    &extra_allowed_attributes,
902                    &body.items(db),
903                    plugin_diagnostics,
904                );
905            }
906        }
907        ast::ModuleItem::Impl(item) => {
908            if let ast::MaybeImplBody::Some(body) = item.body(db) {
909                validate_attributes_element_list(
910                    db,
911                    allowed_attributes,
912                    &extra_allowed_attributes,
913                    &body.items(db),
914                    plugin_diagnostics,
915                );
916            }
917        }
918        ast::ModuleItem::Struct(item) => {
919            validate_attributes_element_list(
920                db,
921                allowed_attributes,
922                &extra_allowed_attributes,
923                &item.members(db),
924                plugin_diagnostics,
925            );
926        }
927        ast::ModuleItem::Enum(item) => {
928            validate_attributes_element_list(
929                db,
930                allowed_attributes,
931                &extra_allowed_attributes,
932                &item.variants(db),
933                plugin_diagnostics,
934            );
935        }
936        _ => {}
937    }
938}
939
940/// Returns all the path leaves under a given use item.
941pub fn get_all_path_leaves(db: &dyn SyntaxGroup, use_item: &ast::ItemUse) -> Vec<ast::UsePathLeaf> {
942    let mut res = vec![];
943    let mut stack = vec![use_item.use_path(db)];
944    while let Some(use_path) = stack.pop() {
945        match use_path {
946            ast::UsePath::Leaf(use_path) => res.push(use_path),
947            ast::UsePath::Single(use_path) => stack.push(use_path.use_path(db)),
948            ast::UsePath::Multi(use_path) => {
949                stack.extend(use_path.use_paths(db).elements(db).into_iter().rev())
950            }
951            ast::UsePath::Star(_) => {}
952        }
953    }
954    res
955}
956
957/// Returns all the path stars under a given use item.
958pub fn get_all_path_stars(db: &dyn SyntaxGroup, use_item: &ast::ItemUse) -> Vec<ast::UsePathStar> {
959    let mut res = vec![];
960    let mut stack = vec![use_item.use_path(db)];
961    while let Some(use_path) = stack.pop() {
962        match use_path {
963            ast::UsePath::Leaf(_) => {}
964            ast::UsePath::Single(use_path) => stack.push(use_path.use_path(db)),
965            ast::UsePath::Multi(use_path) => {
966                stack.extend(use_path.use_paths(db).elements(db).into_iter().rev())
967            }
968            ast::UsePath::Star(use_path) => res.push(use_path),
969        }
970    }
971    res
972}
973
974/// Returns all the constant definitions of the given module.
975pub fn module_constants(
976    db: &dyn DefsGroup,
977    module_id: ModuleId,
978) -> Maybe<Arc<OrderedHashMap<ConstantId, ast::ItemConstant>>> {
979    Ok(db.priv_module_data(module_id)?.constants)
980}
981pub fn module_constants_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[ConstantId]>> {
982    Ok(db.module_constants(module_id)?.keys().copied().collect_vec().into())
983}
984pub fn module_constant_by_id(
985    db: &dyn DefsGroup,
986    constant_id: ConstantId,
987) -> Maybe<Option<ast::ItemConstant>> {
988    let module_constants = db.module_constants(constant_id.module_file_id(db.upcast()).0)?;
989    Ok(module_constants.get(&constant_id).cloned())
990}
991
992/// Returns all the *direct* submodules of the given module - including those generated by macro
993/// plugins. To get all the submodules including nested modules, use [`collect_modules_under`].
994fn module_submodules(
995    db: &dyn DefsGroup,
996    module_id: ModuleId,
997) -> Maybe<Arc<OrderedHashMap<SubmoduleId, ast::ItemModule>>> {
998    Ok(db.priv_module_data(module_id)?.submodules)
999}
1000fn module_submodules_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[SubmoduleId]>> {
1001    Ok(db.module_submodules(module_id)?.keys().copied().collect_vec().into())
1002}
1003pub fn module_submodule_by_id(
1004    db: &dyn DefsGroup,
1005    submodule_id: SubmoduleId,
1006) -> Maybe<Option<ast::ItemModule>> {
1007    let module_submodules = db.module_submodules(submodule_id.module_file_id(db.upcast()).0)?;
1008    Ok(module_submodules.get(&submodule_id).cloned())
1009}
1010
1011/// Returns all the free functions of the given module.
1012pub fn module_free_functions(
1013    db: &dyn DefsGroup,
1014    module_id: ModuleId,
1015) -> Maybe<Arc<OrderedHashMap<FreeFunctionId, ast::FunctionWithBody>>> {
1016    Ok(db.priv_module_data(module_id)?.free_functions)
1017}
1018pub fn module_free_functions_ids(
1019    db: &dyn DefsGroup,
1020    module_id: ModuleId,
1021) -> Maybe<Arc<[FreeFunctionId]>> {
1022    Ok(db.module_free_functions(module_id)?.keys().copied().collect_vec().into())
1023}
1024pub fn module_free_function_by_id(
1025    db: &dyn DefsGroup,
1026    free_function_id: FreeFunctionId,
1027) -> Maybe<Option<ast::FunctionWithBody>> {
1028    let module_free_functions =
1029        db.module_free_functions(free_function_id.module_file_id(db.upcast()).0)?;
1030    Ok(module_free_functions.get(&free_function_id).cloned())
1031}
1032
1033/// Returns all the uses of the given module.
1034pub fn module_uses(
1035    db: &dyn DefsGroup,
1036    module_id: ModuleId,
1037) -> Maybe<Arc<OrderedHashMap<UseId, ast::UsePathLeaf>>> {
1038    Ok(db.priv_module_data(module_id)?.uses)
1039}
1040pub fn module_uses_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[UseId]>> {
1041    Ok(db.module_uses(module_id)?.keys().copied().collect_vec().into())
1042}
1043pub fn module_use_by_id(db: &dyn DefsGroup, use_id: UseId) -> Maybe<Option<ast::UsePathLeaf>> {
1044    let module_uses = db.module_uses(use_id.module_file_id(db.upcast()).0)?;
1045    Ok(module_uses.get(&use_id).cloned())
1046}
1047
1048/// Returns the `use *` of the given module, by its ID.
1049pub fn module_global_use_by_id(
1050    db: &dyn DefsGroup,
1051    global_use_id: GlobalUseId,
1052) -> Maybe<Option<ast::UsePathStar>> {
1053    let module_global_uses = db.module_global_uses(global_use_id.module_file_id(db.upcast()).0)?;
1054    Ok(module_global_uses.get(&global_use_id).cloned())
1055}
1056
1057/// Returns all the structs of the given module.
1058pub fn module_structs(
1059    db: &dyn DefsGroup,
1060    module_id: ModuleId,
1061) -> Maybe<Arc<OrderedHashMap<StructId, ast::ItemStruct>>> {
1062    Ok(db.priv_module_data(module_id)?.structs)
1063}
1064pub fn module_structs_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[StructId]>> {
1065    Ok(db.module_structs(module_id)?.keys().copied().collect_vec().into())
1066}
1067pub fn module_struct_by_id(
1068    db: &dyn DefsGroup,
1069    struct_id: StructId,
1070) -> Maybe<Option<ast::ItemStruct>> {
1071    let module_structs = db.module_structs(struct_id.module_file_id(db.upcast()).0)?;
1072    Ok(module_structs.get(&struct_id).cloned())
1073}
1074
1075/// Returns all the enums of the given module.
1076pub fn module_enums(
1077    db: &dyn DefsGroup,
1078    module_id: ModuleId,
1079) -> Maybe<Arc<OrderedHashMap<EnumId, ast::ItemEnum>>> {
1080    Ok(db.priv_module_data(module_id)?.enums)
1081}
1082pub fn module_enums_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[EnumId]>> {
1083    Ok(db.module_enums(module_id)?.keys().copied().collect_vec().into())
1084}
1085pub fn module_enum_by_id(db: &dyn DefsGroup, enum_id: EnumId) -> Maybe<Option<ast::ItemEnum>> {
1086    let module_enums = db.module_enums(enum_id.module_file_id(db.upcast()).0)?;
1087    Ok(module_enums.get(&enum_id).cloned())
1088}
1089
1090/// Returns all the type aliases of the given module.
1091pub fn module_type_aliases(
1092    db: &dyn DefsGroup,
1093    module_id: ModuleId,
1094) -> Maybe<Arc<OrderedHashMap<ModuleTypeAliasId, ast::ItemTypeAlias>>> {
1095    Ok(db.priv_module_data(module_id)?.type_aliases)
1096}
1097pub fn module_type_aliases_ids(
1098    db: &dyn DefsGroup,
1099    module_id: ModuleId,
1100) -> Maybe<Arc<[ModuleTypeAliasId]>> {
1101    Ok(db.module_type_aliases(module_id)?.keys().copied().collect_vec().into())
1102}
1103pub fn module_type_alias_by_id(
1104    db: &dyn DefsGroup,
1105    module_type_alias_id: ModuleTypeAliasId,
1106) -> Maybe<Option<ast::ItemTypeAlias>> {
1107    let module_type_aliases =
1108        db.module_type_aliases(module_type_alias_id.module_file_id(db.upcast()).0)?;
1109    Ok(module_type_aliases.get(&module_type_alias_id).cloned())
1110}
1111
1112/// Returns all the impl aliases of the given module.
1113pub fn module_impl_aliases(
1114    db: &dyn DefsGroup,
1115    module_id: ModuleId,
1116) -> Maybe<Arc<OrderedHashMap<ImplAliasId, ast::ItemImplAlias>>> {
1117    Ok(db.priv_module_data(module_id)?.impl_aliases)
1118}
1119pub fn module_impl_aliases_ids(
1120    db: &dyn DefsGroup,
1121    module_id: ModuleId,
1122) -> Maybe<Arc<[ImplAliasId]>> {
1123    Ok(db.module_impl_aliases(module_id)?.keys().copied().collect_vec().into())
1124}
1125pub fn module_impl_alias_by_id(
1126    db: &dyn DefsGroup,
1127    impl_alias_id: ImplAliasId,
1128) -> Maybe<Option<ast::ItemImplAlias>> {
1129    let module_impl_aliases =
1130        db.module_impl_aliases(impl_alias_id.module_file_id(db.upcast()).0)?;
1131    Ok(module_impl_aliases.get(&impl_alias_id).cloned())
1132}
1133
1134/// Returns all the traits of the given module.
1135pub fn module_traits(
1136    db: &dyn DefsGroup,
1137    module_id: ModuleId,
1138) -> Maybe<Arc<OrderedHashMap<TraitId, ast::ItemTrait>>> {
1139    Ok(db.priv_module_data(module_id)?.traits)
1140}
1141pub fn module_traits_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[TraitId]>> {
1142    Ok(db.module_traits(module_id)?.keys().copied().collect_vec().into())
1143}
1144pub fn module_trait_by_id(db: &dyn DefsGroup, trait_id: TraitId) -> Maybe<Option<ast::ItemTrait>> {
1145    let module_traits = db.module_traits(trait_id.module_file_id(db.upcast()).0)?;
1146    Ok(module_traits.get(&trait_id).cloned())
1147}
1148
1149/// Returns all the impls of the given module.
1150pub fn module_impls(
1151    db: &dyn DefsGroup,
1152    module_id: ModuleId,
1153) -> Maybe<Arc<OrderedHashMap<ImplDefId, ast::ItemImpl>>> {
1154    Ok(db.priv_module_data(module_id)?.impls)
1155}
1156pub fn module_impls_ids(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[ImplDefId]>> {
1157    Ok(db.module_impls(module_id)?.keys().copied().collect_vec().into())
1158}
1159pub fn module_impl_by_id(
1160    db: &dyn DefsGroup,
1161    impl_def_id: ImplDefId,
1162) -> Maybe<Option<ast::ItemImpl>> {
1163    let module_impls = db.module_impls(impl_def_id.module_file_id(db.upcast()).0)?;
1164    Ok(module_impls.get(&impl_def_id).cloned())
1165}
1166
1167/// Returns all the extern_types of the given module.
1168pub fn module_extern_types(
1169    db: &dyn DefsGroup,
1170    module_id: ModuleId,
1171) -> Maybe<Arc<OrderedHashMap<ExternTypeId, ast::ItemExternType>>> {
1172    Ok(db.priv_module_data(module_id)?.extern_types)
1173}
1174pub fn module_extern_types_ids(
1175    db: &dyn DefsGroup,
1176    module_id: ModuleId,
1177) -> Maybe<Arc<[ExternTypeId]>> {
1178    Ok(db.module_extern_types(module_id)?.keys().copied().collect_vec().into())
1179}
1180pub fn module_extern_type_by_id(
1181    db: &dyn DefsGroup,
1182    extern_type_id: ExternTypeId,
1183) -> Maybe<Option<ast::ItemExternType>> {
1184    let module_extern_types =
1185        db.module_extern_types(extern_type_id.module_file_id(db.upcast()).0)?;
1186    Ok(module_extern_types.get(&extern_type_id).cloned())
1187}
1188
1189/// Returns all the extern_functions of the given module.
1190pub fn module_extern_functions(
1191    db: &dyn DefsGroup,
1192    module_id: ModuleId,
1193) -> Maybe<Arc<OrderedHashMap<ExternFunctionId, ast::ItemExternFunction>>> {
1194    Ok(db.priv_module_data(module_id)?.extern_functions)
1195}
1196pub fn module_extern_functions_ids(
1197    db: &dyn DefsGroup,
1198    module_id: ModuleId,
1199) -> Maybe<Arc<[ExternFunctionId]>> {
1200    Ok(db.module_extern_functions(module_id)?.keys().copied().collect_vec().into())
1201}
1202pub fn module_extern_function_by_id(
1203    db: &dyn DefsGroup,
1204    extern_function_id: ExternFunctionId,
1205) -> Maybe<Option<ast::ItemExternFunction>> {
1206    let module_extern_functions =
1207        db.module_extern_functions(extern_function_id.module_file_id(db.upcast()).0)?;
1208    Ok(module_extern_functions.get(&extern_function_id).cloned())
1209}
1210
1211pub fn module_ancestors(db: &dyn DefsGroup, module_id: ModuleId) -> OrderedHashSet<ModuleId> {
1212    let mut current = module_id;
1213    let mut ancestors = OrderedHashSet::default();
1214    while let ModuleId::Submodule(submodule_id) = current {
1215        let parent = submodule_id.parent_module(db);
1216        ancestors.insert(parent);
1217        current = parent
1218    }
1219    ancestors
1220}
1221
1222/// Returns the generated_file_infos of the given module.
1223pub fn module_generated_file_aux_data(
1224    db: &dyn DefsGroup,
1225    module_id: ModuleId,
1226) -> Maybe<Arc<[Option<DynGeneratedFileAuxData>]>> {
1227    Ok(db.priv_module_data(module_id)?.generated_file_aux_data.into())
1228}
1229
1230/// Returns all the plugin diagnostics of the given module.
1231pub fn module_plugin_diagnostics(
1232    db: &dyn DefsGroup,
1233    module_id: ModuleId,
1234) -> Maybe<Arc<[(ModuleFileId, PluginDiagnostic)]>> {
1235    Ok(db.priv_module_data(module_id)?.plugin_diagnostics.into())
1236}
1237
1238/// Diagnostic notes for diagnostics originating in the plugin generated files identified by
1239/// [`FileId`].
1240pub fn module_plugin_diagnostics_notes(
1241    db: &dyn DefsGroup,
1242    module_id: ModuleId,
1243) -> Maybe<Arc<PluginFileDiagnosticNotes>> {
1244    Ok(db.priv_module_data(module_id)?.diagnostics_notes.into())
1245}
1246
1247fn module_items(db: &dyn DefsGroup, module_id: ModuleId) -> Maybe<Arc<[ModuleItemId]>> {
1248    Ok(db.priv_module_data(module_id)?.items)
1249}
1250
1251fn module_global_uses(
1252    db: &dyn DefsGroup,
1253    module_id: ModuleId,
1254) -> Maybe<Arc<OrderedHashMap<GlobalUseId, ast::UsePathStar>>> {
1255    Ok(db.priv_module_data(module_id)?.global_uses)
1256}
1257
1258fn module_item_name_stable_ptr(
1259    db: &dyn DefsGroup,
1260    module_id: ModuleId,
1261    item_id: ModuleItemId,
1262) -> Maybe<SyntaxStablePtrId> {
1263    let data = db.priv_module_data(module_id)?;
1264    let db = db.upcast();
1265    Ok(match &item_id {
1266        ModuleItemId::Constant(id) => data.constants[id].name(db).stable_ptr().untyped(),
1267        ModuleItemId::Submodule(id) => data.submodules[id].name(db).stable_ptr().untyped(),
1268        ModuleItemId::Use(id) => data.uses[id].name_stable_ptr(db),
1269        ModuleItemId::FreeFunction(id) => {
1270            data.free_functions[id].declaration(db).name(db).stable_ptr().untyped()
1271        }
1272        ModuleItemId::Struct(id) => data.structs[id].name(db).stable_ptr().untyped(),
1273        ModuleItemId::Enum(id) => data.enums[id].name(db).stable_ptr().untyped(),
1274        ModuleItemId::TypeAlias(id) => data.type_aliases[id].name(db).stable_ptr().untyped(),
1275        ModuleItemId::ImplAlias(id) => data.impl_aliases[id].name(db).stable_ptr().untyped(),
1276        ModuleItemId::Trait(id) => data.traits[id].name(db).stable_ptr().untyped(),
1277        ModuleItemId::Impl(id) => data.impls[id].name(db).stable_ptr().untyped(),
1278        ModuleItemId::ExternType(id) => data.extern_types[id].name(db).stable_ptr().untyped(),
1279        ModuleItemId::ExternFunction(id) => {
1280            data.extern_functions[id].declaration(db).name(db).stable_ptr().untyped()
1281        }
1282    })
1283}
1284
1285pub trait DefsGroupEx: DefsGroup {
1286    /// Overrides the default macro plugins available for [`CrateId`] with `plugins`.
1287    ///
1288    /// *Note*: Sets the following Salsa input: `DefsGroup::macro_plugin_overrides`.
1289    fn set_override_crate_macro_plugins(
1290        &mut self,
1291        crate_id: CrateId,
1292        plugins: Arc<[MacroPluginId]>,
1293    ) {
1294        let mut overrides = self.macro_plugin_overrides().as_ref().clone();
1295        overrides.insert(crate_id, plugins);
1296        self.set_macro_plugin_overrides(Arc::new(overrides));
1297    }
1298
1299    /// Overrides the default inline macro plugins available for [`CrateId`] with `plugins`.
1300    ///
1301    /// *Note*: Sets the following Salsa input: `DefsGroup::inline_macro_plugin_overrides`.
1302    fn set_override_crate_inline_macro_plugins(
1303        &mut self,
1304        crate_id: CrateId,
1305        plugins: Arc<OrderedHashMap<String, InlineMacroExprPluginId>>,
1306    ) {
1307        let mut overrides = self.inline_macro_plugin_overrides().as_ref().clone();
1308        overrides.insert(crate_id, plugins);
1309        self.set_inline_macro_plugin_overrides(Arc::new(overrides));
1310    }
1311}
1312
1313impl<T: DefsGroup + ?Sized> DefsGroupEx for T {}