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