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