1use std::collections::VecDeque;
2use std::sync::Arc;
3
4use cairo_lang_diagnostics::{
5 DiagnosticNote, Maybe, MaybeAsRef, PluginFileDiagnosticNotes, ToMaybe, skip_diagnostic,
6};
7use cairo_lang_filesystem::db::{ExtAsVirtual, FilesGroup, files_group_input};
8use cairo_lang_filesystem::ids::{
9 CrateId, CrateInput, Directory, FileId, FileKind, FileLongId, SmolStrId, Tracked, VirtualFile,
10};
11use cairo_lang_parser::db::ParserGroup;
12use cairo_lang_syntax::attribute::consts::{
13 ALLOW_ATTR, ALLOW_ATTR_ATTR, DEPRECATED_ATTR, FEATURE_ATTR, FMT_SKIP_ATTR,
14 IMPLICIT_PRECEDENCE_ATTR, INLINE_ATTR, INTERNAL_ATTR, MUST_USE_ATTR, PATH_ATTR, PHANTOM_ATTR,
15 STARKNET_INTERFACE_ATTR, UNSTABLE_ATTR,
16};
17use cairo_lang_syntax::attribute::structured::AttributeStructurize;
18use cairo_lang_syntax::node::ast::MaybeModuleBody;
19use cairo_lang_syntax::node::helpers::QueryAttrs;
20use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
21use cairo_lang_syntax::node::{Terminal, TypedStablePtr, TypedSyntaxNode, ast};
22use cairo_lang_utils::Intern;
23use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
24use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
25use itertools::{Itertools, chain};
26use salsa::{Database, Setter};
27
28use crate::cache::{DefCacheLoadingData, load_cached_crate_modules};
29use crate::ids::*;
30use crate::plugin::{DynGeneratedFileAuxData, MacroPlugin, MacroPluginMetadata, PluginDiagnostic};
31use crate::plugin_utils::try_extract_unnamed_arg;
32
33#[salsa::input]
34pub struct DefsGroupInput {
35 #[returns(ref)]
36 pub default_macro_plugins: Option<Vec<MacroPluginLongId>>,
37 #[returns(ref)]
38 pub macro_plugin_overrides: Option<OrderedHashMap<CrateInput, Arc<[MacroPluginLongId]>>>,
39 #[returns(ref)]
40 pub default_inline_macro_plugins: Option<OrderedHashMap<String, InlineMacroExprPluginLongId>>,
41 #[returns(ref)]
42 pub inline_macro_plugin_overrides: Option<
43 OrderedHashMap<CrateInput, Arc<OrderedHashMap<String, InlineMacroExprPluginLongId>>>,
44 >,
45}
46
47#[salsa::tracked(returns(ref))]
50pub fn defs_group_input(db: &dyn Database) -> DefsGroupInput {
51 DefsGroupInput::new(db, None, None, None, None)
52}
53
54pub trait DefsGroup: Database {
57 fn default_macro_plugins_input(&self) -> &[MacroPluginLongId] {
58 defs_group_input(self.as_dyn_database()).default_macro_plugins(self).as_ref().unwrap()
59 }
60
61 fn macro_plugin_overrides_input(
62 &self,
63 ) -> &OrderedHashMap<CrateInput, Arc<[MacroPluginLongId]>> {
64 defs_group_input(self.as_dyn_database()).macro_plugin_overrides(self).as_ref().unwrap()
65 }
66
67 fn inline_macro_plugin_overrides_input(
68 &self,
69 ) -> &OrderedHashMap<CrateInput, Arc<OrderedHashMap<String, InlineMacroExprPluginLongId>>> {
70 defs_group_input(self.as_dyn_database())
71 .inline_macro_plugin_overrides(self)
72 .as_ref()
73 .unwrap()
74 }
75
76 fn default_inline_macro_plugins_input(
77 &self,
78 ) -> &OrderedHashMap<String, InlineMacroExprPluginLongId> {
79 defs_group_input(self.as_dyn_database())
80 .default_inline_macro_plugins(self)
81 .as_ref()
82 .unwrap()
83 }
84
85 fn default_macro_plugins<'db>(&'db self) -> &'db [MacroPluginId<'db>] {
90 default_macro_plugins(self.as_dyn_database())
91 }
92
93 fn macro_plugin_overrides<'db>(
95 &'db self,
96 ) -> &'db OrderedHashMap<CrateId<'db>, Vec<MacroPluginId<'db>>> {
97 macro_plugin_overrides(self.as_dyn_database())
98 }
99
100 fn crate_macro_plugins<'db>(&'db self, crate_id: CrateId<'db>) -> &'db [MacroPluginId<'db>] {
105 crate_macro_plugins(self.as_dyn_database(), crate_id)
106 }
107
108 fn default_inline_macro_plugins<'db>(
110 &'db self,
111 ) -> &'db OrderedHashMap<String, InlineMacroExprPluginId<'db>> {
112 default_inline_macro_plugins(self.as_dyn_database())
113 }
114
115 fn inline_macro_plugin_overrides<'db>(
117 &'db self,
118 ) -> &'db OrderedHashMap<CrateId<'db>, OrderedHashMap<String, InlineMacroExprPluginId<'db>>>
119 {
120 inline_macro_plugin_overrides(self.as_dyn_database())
121 }
122
123 fn crate_inline_macro_plugins<'db>(
128 &'db self,
129 crate_id: CrateId<'db>,
130 ) -> &'db OrderedHashMap<String, InlineMacroExprPluginId<'db>> {
131 crate_inline_macro_plugins(self.as_dyn_database(), crate_id)
132 }
133
134 fn allowed_attributes<'db>(
137 &'db self,
138 crate_id: CrateId<'db>,
139 ) -> &'db OrderedHashSet<SmolStrId<'db>> {
140 allowed_attributes(self.as_dyn_database(), crate_id)
141 }
142
143 fn allowed_statement_attributes<'db>(&'db self) -> &'db OrderedHashSet<SmolStrId<'db>> {
146 allowed_statement_attributes(self.as_dyn_database())
147 }
148
149 fn declared_derives<'db>(
152 &'db self,
153 crate_id: CrateId<'db>,
154 ) -> &'db OrderedHashSet<SmolStrId<'db>> {
155 declared_derives(self.as_dyn_database(), crate_id)
156 }
157
158 fn declared_phantom_type_attributes<'db>(
161 &'db self,
162 crate_id: CrateId<'db>,
163 ) -> &'db OrderedHashSet<SmolStrId<'db>> {
164 declared_phantom_type_attributes(self.as_dyn_database(), crate_id)
165 }
166
167 fn is_submodule_inline<'db>(&self, submodule_id: SubmoduleId<'db>) -> bool {
169 is_submodule_inline(self.as_dyn_database(), submodule_id)
170 }
171
172 fn module_main_file<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<FileId<'db>> {
176 module_main_file(self.as_dyn_database(), module_id)
177 }
178 fn module_files<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db [FileId<'db>]> {
180 module_files(self.as_dyn_database(), module_id)
181 }
182 fn module_dir<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db Directory<'db>> {
184 module_dir(self.as_dyn_database(), module_id)
185 }
186
187 fn crate_modules<'db>(&'db self, crate_id: CrateId<'db>) -> &'db [ModuleId<'db>] {
189 crate_modules(self.as_dyn_database(), crate_id)
190 }
191 fn file_modules<'db>(&'db self, file_id: FileId<'db>) -> Maybe<&'db Vec<ModuleId<'db>>> {
192 file_modules(self.as_dyn_database(), file_id).maybe_as_ref()
193 }
194
195 fn cached_crate_modules<'db>(
198 &'db self,
199 crate_id: CrateId<'db>,
200 ) -> Option<ModuleDataCacheAndLoadingData<'db>> {
201 cached_crate_modules(self.as_dyn_database(), crate_id)
202 }
203 fn module_submodules_ids<'db>(
204 &'db self,
205 module_id: ModuleId<'db>,
206 ) -> Maybe<&'db [SubmoduleId<'db>]> {
207 module_submodules_ids(self.as_dyn_database(), module_id)
208 }
209 fn module_constants_ids<'db>(
210 &'db self,
211 module_id: ModuleId<'db>,
212 ) -> Maybe<&'db [ConstantId<'db>]> {
213 module_constants_ids(self.as_dyn_database(), module_id)
214 }
215 fn module_constant_by_id<'db>(
216 &'db self,
217 constant_data: ConstantId<'db>,
218 ) -> Maybe<ast::ItemConstant<'db>> {
219 module_constant_by_id(self.as_dyn_database(), constant_data)
220 }
221 fn module_free_functions_ids<'db>(
222 &'db self,
223 module_id: ModuleId<'db>,
224 ) -> Maybe<&'db [FreeFunctionId<'db>]> {
225 module_free_functions_ids(self.as_dyn_database(), module_id)
226 }
227 fn module_free_function_by_id<'db>(
228 &'db self,
229 free_function_id: FreeFunctionId<'db>,
230 ) -> Maybe<ast::FunctionWithBody<'db>> {
231 module_free_function_by_id(self.as_dyn_database(), free_function_id)
232 }
233 fn module_item_name_stable_ptr<'db>(
235 &'db self,
236 module_id: ModuleId<'db>,
237 item_id: ModuleItemId<'db>,
238 ) -> Maybe<SyntaxStablePtrId<'db>> {
239 module_item_name_stable_ptr(self.as_dyn_database(), module_id, item_id)
240 }
241 fn module_uses_ids<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db [UseId<'db>]> {
242 module_uses_ids(self.as_dyn_database(), module_id)
243 }
244 fn module_use_by_id<'db>(&'db self, use_id: UseId<'db>) -> Maybe<ast::UsePathLeaf<'db>> {
245 module_use_by_id(self.as_dyn_database(), use_id)
246 }
247 fn module_global_use_by_id<'db>(
248 &'db self,
249 global_use_id: GlobalUseId<'db>,
250 ) -> Maybe<ast::UsePathStar<'db>> {
251 module_global_use_by_id(self.as_dyn_database(), global_use_id)
252 }
253 fn module_structs_ids<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db [StructId<'db>]> {
254 module_structs_ids(self.as_dyn_database(), module_id)
255 }
256 fn module_struct_by_id<'db>(
257 &'db self,
258 struct_id: StructId<'db>,
259 ) -> Maybe<ast::ItemStruct<'db>> {
260 module_struct_by_id(self.as_dyn_database(), struct_id)
261 }
262 fn module_enums_ids<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db [EnumId<'db>]> {
263 module_enums_ids(self.as_dyn_database(), module_id)
264 }
265 fn module_enum_by_id<'db>(&'db self, enum_id: EnumId<'db>) -> Maybe<ast::ItemEnum<'db>> {
266 module_enum_by_id(self.as_dyn_database(), enum_id)
267 }
268 fn module_type_aliases_ids<'db>(
269 &'db self,
270 module_id: ModuleId<'db>,
271 ) -> Maybe<&'db [ModuleTypeAliasId<'db>]> {
272 module_type_aliases_ids(self.as_dyn_database(), module_id)
273 }
274 fn module_type_alias_by_id<'db>(
275 &'db self,
276 module_type_alias_id: ModuleTypeAliasId<'db>,
277 ) -> Maybe<ast::ItemTypeAlias<'db>> {
278 module_type_alias_by_id(self.as_dyn_database(), module_type_alias_id)
279 }
280 fn module_impl_aliases_ids<'db>(
281 &'db self,
282 module_id: ModuleId<'db>,
283 ) -> Maybe<&'db [ImplAliasId<'db>]> {
284 module_impl_aliases_ids(self.as_dyn_database(), module_id)
285 }
286 fn module_impl_alias_by_id<'db>(
287 &'db self,
288 impl_alias_id: ImplAliasId<'db>,
289 ) -> Maybe<ast::ItemImplAlias<'db>> {
290 module_impl_alias_by_id(self.as_dyn_database(), impl_alias_id)
291 }
292 fn module_traits_ids<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db [TraitId<'db>]> {
293 module_traits_ids(self.as_dyn_database(), module_id)
294 }
295 fn module_trait_by_id<'db>(&'db self, trait_id: TraitId<'db>) -> Maybe<ast::ItemTrait<'db>> {
296 module_trait_by_id(self.as_dyn_database(), trait_id)
297 }
298 fn module_impls_ids<'db>(&'db self, module_id: ModuleId<'db>) -> Maybe<&'db [ImplDefId<'db>]> {
299 module_impls_ids(self.as_dyn_database(), module_id)
300 }
301 fn module_impl_by_id<'db>(&'db self, impl_id: ImplDefId<'db>) -> Maybe<ast::ItemImpl<'db>> {
302 module_impl_by_id(self.as_dyn_database(), impl_id)
303 }
304 fn module_extern_types_ids<'db>(
305 &'db self,
306 module_id: ModuleId<'db>,
307 ) -> Maybe<&'db [ExternTypeId<'db>]> {
308 module_extern_types_ids(self.as_dyn_database(), module_id)
309 }
310 fn module_extern_type_by_id<'db>(
311 &'db self,
312 extern_type_id: ExternTypeId<'db>,
313 ) -> Maybe<ast::ItemExternType<'db>> {
314 module_extern_type_by_id(self.as_dyn_database(), extern_type_id)
315 }
316 fn module_extern_functions_ids<'db>(
317 &'db self,
318 module_id: ModuleId<'db>,
319 ) -> Maybe<&'db [ExternFunctionId<'db>]> {
320 module_extern_functions_ids(self.as_dyn_database(), module_id)
321 }
322 fn module_extern_function_by_id<'db>(
323 &'db self,
324 extern_function_id: ExternFunctionId<'db>,
325 ) -> Maybe<ast::ItemExternFunction<'db>> {
326 module_extern_function_by_id(self.as_dyn_database(), extern_function_id)
327 }
328
329 fn module_macro_declarations_ids<'db>(
331 &'db self,
332 module_id: ModuleId<'db>,
333 ) -> Maybe<&'db [MacroDeclarationId<'db>]> {
334 module_macro_declarations_ids(self.as_dyn_database(), module_id)
335 }
336 fn module_macro_declaration_by_id<'db>(
338 &'db self,
339 macro_declaration_id: MacroDeclarationId<'db>,
340 ) -> Maybe<ast::ItemMacroDeclaration<'db>> {
341 module_macro_declaration_by_id(self.as_dyn_database(), macro_declaration_id)
342 }
343
344 fn module_macro_calls_ids<'db>(
346 &'db self,
347 module_id: ModuleId<'db>,
348 ) -> Maybe<&'db [MacroCallId<'db>]> {
349 module_macro_calls_ids(self.as_dyn_database(), module_id)
350 }
351 fn module_macro_call_by_id<'db>(
353 &'db self,
354 macro_call_id: MacroCallId<'db>,
355 ) -> Maybe<ast::ItemInlineMacro<'db>> {
356 module_macro_call_by_id(self.as_dyn_database(), macro_call_id)
357 }
358 fn module_ancestors<'db>(
360 &'db self,
361 module_id: ModuleId<'db>,
362 ) -> &'db OrderedHashSet<ModuleId<'db>> {
363 module_ancestors_helper(self.as_dyn_database(), (), module_id)
364 }
365 fn module_perceived_module<'db>(&'db self, module_id: ModuleId<'db>) -> ModuleId<'db> {
369 module_perceived_module_helper(self.as_dyn_database(), (), module_id)
370 }
371}
372
373impl<T: Database + ?Sized> DefsGroup for T {}
374
375pub fn init_defs_group(db: &mut dyn Database) {
377 defs_group_input(db).set_macro_plugin_overrides(db).to(Some(OrderedHashMap::default()));
378 defs_group_input(db).set_inline_macro_plugin_overrides(db).to(Some(OrderedHashMap::default()));
379}
380
381#[salsa::tracked(returns(ref))]
382fn default_macro_plugins_helper<'db>(db: &'db dyn Database) -> Vec<MacroPluginId<'db>> {
383 db.default_macro_plugins_input()
384 .iter()
385 .map(|plugin| MacroPluginId::new(db, plugin.clone()))
386 .collect()
387}
388
389pub fn default_macro_plugins<'db>(db: &'db dyn Database) -> &'db [MacroPluginId<'db>] {
390 default_macro_plugins_helper(db)
391}
392
393#[salsa::tracked(returns(ref))]
394pub fn macro_plugin_overrides<'db>(
395 db: &'db dyn Database,
396) -> OrderedHashMap<CrateId<'db>, Vec<MacroPluginId<'db>>> {
397 let inp = db.macro_plugin_overrides_input();
398 inp.iter()
399 .map(|(crate_id, plugins)| {
400 (
401 crate_id.clone().into_crate_long_id(db).intern(db),
402 plugins.iter().map(|plugin| plugin.clone().intern(db)).collect(),
403 )
404 })
405 .collect()
406}
407
408#[salsa::tracked(returns(ref))]
409pub fn inline_macro_plugin_overrides<'db>(
410 db: &'db dyn Database,
411) -> OrderedHashMap<CrateId<'db>, OrderedHashMap<String, InlineMacroExprPluginId<'db>>> {
412 let inp = db.inline_macro_plugin_overrides_input();
413 inp.iter()
414 .map(|(crate_id, plugins)| {
415 (
416 crate_id.clone().into_crate_long_id(db).intern(db),
417 plugins
418 .iter()
419 .map(|(name, plugin)| (name.clone(), plugin.clone().intern(db)))
420 .collect(),
421 )
422 })
423 .collect()
424}
425
426#[salsa::tracked(returns(ref))]
427pub fn default_inline_macro_plugins<'db>(
428 db: &'db dyn Database,
429) -> OrderedHashMap<String, InlineMacroExprPluginId<'db>> {
430 let inp = db.default_inline_macro_plugins_input();
431 inp.iter().map(|(name, plugin)| (name.clone(), plugin.clone().intern(db))).collect()
432}
433
434fn crate_macro_plugins<'db>(
435 db: &'db dyn Database,
436 crate_id: CrateId<'db>,
437) -> &'db [MacroPluginId<'db>] {
438 macro_plugin_overrides(db).get(&crate_id).unwrap_or_else(|| default_macro_plugins_helper(db))
439}
440
441fn crate_inline_macro_plugins<'db>(
442 db: &'db dyn Database,
443 crate_id: CrateId<'db>,
444) -> &'db OrderedHashMap<String, InlineMacroExprPluginId<'db>> {
445 db.inline_macro_plugin_overrides()
446 .get(&crate_id)
447 .unwrap_or_else(|| db.default_inline_macro_plugins())
448}
449
450#[salsa::tracked(returns(ref))]
451fn allowed_attributes<'db>(
452 db: &'db dyn Database,
453 crate_id: CrateId<'db>,
454) -> OrderedHashSet<SmolStrId<'db>> {
455 let base_attrs = [
456 INLINE_ATTR,
457 MUST_USE_ATTR,
458 UNSTABLE_ATTR,
459 DEPRECATED_ATTR,
460 INTERNAL_ATTR,
461 ALLOW_ATTR,
462 ALLOW_ATTR_ATTR,
463 FEATURE_ATTR,
464 PHANTOM_ATTR,
465 IMPLICIT_PRECEDENCE_ATTR,
466 FMT_SKIP_ATTR,
467 PATH_ATTR,
468 STARKNET_INTERFACE_ATTR,
470 ];
471
472 let crate_plugins = db.crate_macro_plugins(crate_id);
473
474 OrderedHashSet::from_iter(chain!(
475 base_attrs.map(|attr| SmolStrId::from(db, attr)),
476 crate_plugins.iter().flat_map(|plugin| plugin.long(db).declared_attributes(db))
477 ))
478}
479
480#[salsa::tracked(returns(ref))]
482fn allowed_statement_attributes<'db>(db: &'db dyn Database) -> OrderedHashSet<SmolStrId<'db>> {
483 let all_attributes = [FMT_SKIP_ATTR, ALLOW_ATTR, FEATURE_ATTR];
484 OrderedHashSet::from_iter(all_attributes.map(|attr| SmolStrId::from(db, attr)))
485}
486
487#[salsa::tracked(returns(ref))]
488fn declared_derives<'db>(
489 db: &'db dyn Database,
490 crate_id: CrateId<'db>,
491) -> OrderedHashSet<SmolStrId<'db>> {
492 OrderedHashSet::from_iter(
493 db.crate_macro_plugins(crate_id)
494 .iter()
495 .flat_map(|plugin| plugin.long(db).declared_derives(db)),
496 )
497}
498
499#[salsa::tracked(returns(ref))]
500fn declared_phantom_type_attributes<'db>(
501 db: &'db dyn Database,
502 crate_id: CrateId<'db>,
503) -> OrderedHashSet<SmolStrId<'db>> {
504 let crate_plugins = db.crate_macro_plugins(crate_id);
505
506 OrderedHashSet::from_iter(chain!(
507 [SmolStrId::from(db, PHANTOM_ATTR)],
508 crate_plugins.iter().flat_map(|plugin| plugin.long(db).phantom_type_attributes(db))
509 ))
510}
511
512#[salsa::tracked]
513fn is_submodule_inline<'db>(db: &'db dyn Database, submodule_id: SubmoduleId<'db>) -> bool {
514 match submodule_id.stable_ptr(db).lookup(db).body(db) {
515 MaybeModuleBody::Some(_) => true,
516 MaybeModuleBody::None(_) => false,
517 }
518}
519
520#[salsa::tracked]
521fn module_main_file_helper<'db>(
522 db: &'db dyn Database,
523 _tracked: Tracked,
524 module_id: ModuleId<'db>,
525) -> Maybe<FileId<'db>> {
526 Ok(match module_id {
527 ModuleId::CrateRoot(crate_id) => {
528 db.crate_config(crate_id).to_maybe()?.root.file(db, "lib.cairo")
529 }
530 ModuleId::Submodule(submodule_id) => {
531 let parent = submodule_id.parent_module(db);
532 if db.is_submodule_inline(submodule_id) {
533 submodule_id.stable_ptr(db).untyped().file_id(db)
537 } else if let Some(path_override) = submodule_path_override(db, submodule_id) {
538 path_override
539 } else {
540 db.module_dir(parent)?
541 .file(db, &format!("{}.cairo", submodule_id.name(db).long(db)))
542 }
543 }
544 ModuleId::MacroCall { generated_file_id, .. } => generated_file_id,
546 })
547}
548
549fn module_main_file<'db>(db: &'db dyn Database, module_id: ModuleId<'db>) -> Maybe<FileId<'db>> {
550 module_main_file_helper(db, (), module_id)
551}
552
553fn module_files<'db>(db: &'db dyn Database, module_id: ModuleId<'db>) -> Maybe<&'db [FileId<'db>]> {
554 Ok(module_id.module_data(db)?.files(db))
555}
556
557#[salsa::tracked(returns(ref))]
559fn module_dir_helper<'db>(
560 db: &'db dyn Database,
561 _tracked: Tracked,
562 module_id: ModuleId<'db>,
563) -> Maybe<Directory<'db>> {
564 match module_id {
565 ModuleId::CrateRoot(crate_id) => {
566 db.crate_config(crate_id).to_maybe().map(|config| config.root.clone())
567 }
568 ModuleId::Submodule(submodule_id) => {
569 let parent = submodule_id.parent_module(db);
570 let name = submodule_id.name(db);
571 Ok(db.module_dir(parent)?.subdir(name.long(db)))
572 }
573 ModuleId::MacroCall { id, .. } => db.module_dir(id.parent_module(db)).cloned(),
576 }
577}
578
579fn submodule_path_override<'db>(
583 db: &'db dyn Database,
584 submodule_id: SubmoduleId<'db>,
585) -> Option<FileId<'db>> {
586 let parent = submodule_id.parent_module(db);
588 let parent_data = parent.module_data(db).ok()?;
589 let item_module_ast = parent_data.submodules(db).get(&submodule_id)?.clone();
590
591 let attr_ast = item_module_ast.find_attr(db, PATH_ATTR)?;
592 let terminal = extract_path_arg(db, &attr_ast.arguments(db))?;
593 let path = terminal.string_value(db)?;
594 fn find_base<'db>(db: &'db dyn Database, module_id: ModuleId<'db>) -> ModuleId<'db> {
596 match module_id {
597 ModuleId::CrateRoot(crate_id) => ModuleId::CrateRoot(crate_id),
598 ModuleId::Submodule(submodule_id) => submodule_id.parent_module(db),
599 ModuleId::MacroCall { id, .. } => find_base(db, id.parent_module(db)),
600 }
601 }
602 let base = find_base(db, parent);
603 Some(db.module_dir(base).ok()?.file(db, &path))
604}
605
606fn module_dir<'db>(db: &'db dyn Database, module_id: ModuleId<'db>) -> Maybe<&'db Directory<'db>> {
607 module_dir_helper(db, (), module_id).maybe_as_ref()
608}
609
610fn collect_modules_under<'db>(
612 db: &'db dyn Database,
613 modules: &mut Vec<ModuleId<'db>>,
614 module_id: ModuleId<'db>,
615) {
616 modules.push(module_id);
617 if let Ok(submodule_ids) = db.module_submodules_ids(module_id) {
618 for submodule_module_id in submodule_ids.iter().copied() {
619 collect_modules_under(db, modules, ModuleId::Submodule(submodule_module_id));
620 }
621 }
622}
623
624#[salsa::tracked(returns(ref))]
626fn crate_modules<'db>(db: &'db dyn Database, crate_id: CrateId<'db>) -> Vec<ModuleId<'db>> {
627 let mut modules = Vec::new();
628 collect_modules_under(db, &mut modules, ModuleId::CrateRoot(crate_id));
629 modules
630}
631
632#[salsa::tracked(returns(ref))]
634fn file_to_module_mapping<'db>(
635 db: &'db dyn Database,
636) -> OrderedHashMap<FileId<'db>, Vec<ModuleId<'db>>> {
637 let mut mapping = OrderedHashMap::<FileId<'db>, Vec<ModuleId<'db>>>::default();
638 for crate_id in db.crates() {
639 for module_id in db.crate_modules(*crate_id).iter().copied() {
640 if let Ok(files) = db.module_files(module_id) {
641 for file_id in files.iter().copied() {
642 match mapping.get_mut(&file_id) {
643 Some(file_modules) => {
644 file_modules.push(module_id);
645 }
646 None => {
647 mapping.insert(file_id, vec![module_id]);
648 }
649 }
650 }
651 }
652 }
653 }
654 mapping
655}
656
657#[salsa::tracked(returns(ref))]
658fn file_modules<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Maybe<Vec<ModuleId<'db>>> {
659 file_to_module_mapping(db).get(&file_id).cloned().to_maybe()
660}
661
662#[salsa::tracked]
663pub struct ModuleData<'db> {
664 #[returns(ref)]
667 pub items: Vec<ModuleItemId<'db>>,
668
669 #[returns(ref)]
672 types_data: ModuleTypesData<'db>,
673 #[returns(ref)]
675 named_items_data: ModuleNamedItemsData<'db>,
676 #[returns(ref)]
678 unnamed_items_data: ModuleUnnamedItemsData<'db>,
679 #[returns(ref)]
681 files_data: ModuleFilesData<'db>,
682}
683
684#[salsa::tracked]
685pub struct ModuleTypesData<'db> {
686 #[returns(ref)]
688 structs: OrderedHashMap<StructId<'db>, ast::ItemStruct<'db>>,
689 #[returns(ref)]
691 enums: OrderedHashMap<EnumId<'db>, ast::ItemEnum<'db>>,
692 #[returns(ref)]
694 type_aliases: OrderedHashMap<ModuleTypeAliasId<'db>, ast::ItemTypeAlias<'db>>,
695 #[returns(ref)]
697 extern_types: OrderedHashMap<ExternTypeId<'db>, ast::ItemExternType<'db>>,
698}
699
700#[salsa::tracked]
701pub struct ModuleNamedItemsData<'db> {
702 #[returns(ref)]
704 constants: OrderedHashMap<ConstantId<'db>, ast::ItemConstant<'db>>,
705 #[returns(ref)]
709 submodules: OrderedHashMap<SubmoduleId<'db>, ast::ItemModule<'db>>,
710 #[returns(ref)]
712 uses: OrderedHashMap<UseId<'db>, ast::UsePathLeaf<'db>>,
713 #[returns(ref)]
714 free_functions: OrderedHashMap<FreeFunctionId<'db>, ast::FunctionWithBody<'db>>,
715 #[returns(ref)]
717 impl_aliases: OrderedHashMap<ImplAliasId<'db>, ast::ItemImplAlias<'db>>,
718 #[returns(ref)]
720 traits: OrderedHashMap<TraitId<'db>, ast::ItemTrait<'db>>,
721 #[returns(ref)]
723 impls: OrderedHashMap<ImplDefId<'db>, ast::ItemImpl<'db>>,
724 #[returns(ref)]
726 extern_functions: OrderedHashMap<ExternFunctionId<'db>, ast::ItemExternFunction<'db>>,
727 #[returns(ref)]
729 macro_declarations: OrderedHashMap<MacroDeclarationId<'db>, ast::ItemMacroDeclaration<'db>>,
730}
731#[salsa::tracked]
732pub struct ModuleUnnamedItemsData<'db> {
733 #[returns(ref)]
735 global_uses: OrderedHashMap<GlobalUseId<'db>, ast::UsePathStar<'db>>,
736 #[returns(ref)]
738 macro_calls: OrderedHashMap<MacroCallId<'db>, ast::ItemInlineMacro<'db>>,
739}
740
741#[salsa::tracked]
742pub struct ModuleFilesData<'db> {
743 #[returns(ref)]
744 files: Vec<FileId<'db>>,
745 #[returns(ref)]
747 generated_file_aux_data: OrderedHashMap<FileId<'db>, Option<DynGeneratedFileAuxData>>,
748 #[returns(ref)]
749 plugin_diagnostics: Vec<(ModuleId<'db>, PluginDiagnostic<'db>)>,
750 #[returns(ref)]
754 diagnostics_notes: PluginFileDiagnosticNotes<'db>,
755}
756
757impl<'db> ModuleData<'db> {
758 pub fn constants(
760 &self,
761 db: &'db dyn Database,
762 ) -> &'db OrderedHashMap<ConstantId<'db>, ast::ItemConstant<'db>> {
763 self.named_items_data(db).constants(db)
764 }
765 pub fn submodules(
767 &self,
768 db: &'db dyn Database,
769 ) -> &'db OrderedHashMap<SubmoduleId<'db>, ast::ItemModule<'db>> {
770 self.named_items_data(db).submodules(db)
771 }
772 pub fn uses(
774 &self,
775 db: &'db dyn Database,
776 ) -> &'db OrderedHashMap<UseId<'db>, ast::UsePathLeaf<'db>> {
777 self.named_items_data(db).uses(db)
778 }
779 pub fn free_functions(
781 &self,
782 db: &'db dyn Database,
783 ) -> &'db OrderedHashMap<FreeFunctionId<'db>, ast::FunctionWithBody<'db>> {
784 self.named_items_data(db).free_functions(db)
785 }
786 pub fn structs(
788 &self,
789 db: &'db dyn Database,
790 ) -> &'db OrderedHashMap<StructId<'db>, ast::ItemStruct<'db>> {
791 self.types_data(db).structs(db)
792 }
793
794 pub fn enums(
796 &self,
797 db: &'db dyn Database,
798 ) -> &'db OrderedHashMap<EnumId<'db>, ast::ItemEnum<'db>> {
799 self.types_data(db).enums(db)
800 }
801
802 pub fn type_aliases(
804 &self,
805 db: &'db dyn Database,
806 ) -> &'db OrderedHashMap<ModuleTypeAliasId<'db>, ast::ItemTypeAlias<'db>> {
807 self.types_data(db).type_aliases(db)
808 }
809
810 pub fn impl_aliases(
812 &self,
813 db: &'db dyn Database,
814 ) -> &'db OrderedHashMap<ImplAliasId<'db>, ast::ItemImplAlias<'db>> {
815 self.named_items_data(db).impl_aliases(db)
816 }
817 pub fn traits(
819 &self,
820 db: &'db dyn Database,
821 ) -> &'db OrderedHashMap<TraitId<'db>, ast::ItemTrait<'db>> {
822 self.named_items_data(db).traits(db)
823 }
824 pub fn impls(
826 &self,
827 db: &'db dyn Database,
828 ) -> &'db OrderedHashMap<ImplDefId<'db>, ast::ItemImpl<'db>> {
829 self.named_items_data(db).impls(db)
830 }
831 pub fn extern_types(
833 &self,
834 db: &'db dyn Database,
835 ) -> &'db OrderedHashMap<ExternTypeId<'db>, ast::ItemExternType<'db>> {
836 self.types_data(db).extern_types(db)
837 }
838 pub fn extern_functions(
840 &self,
841 db: &'db dyn Database,
842 ) -> &'db OrderedHashMap<ExternFunctionId<'db>, ast::ItemExternFunction<'db>> {
843 self.named_items_data(db).extern_functions(db)
844 }
845 pub fn macro_declarations(
847 &self,
848 db: &'db dyn Database,
849 ) -> &'db OrderedHashMap<MacroDeclarationId<'db>, ast::ItemMacroDeclaration<'db>> {
850 self.named_items_data(db).macro_declarations(db)
851 }
852 pub fn global_uses(
854 &self,
855 db: &'db dyn Database,
856 ) -> &'db OrderedHashMap<GlobalUseId<'db>, ast::UsePathStar<'db>> {
857 self.unnamed_items_data(db).global_uses(db)
858 }
859 pub fn macro_calls(
861 &self,
862 db: &'db dyn Database,
863 ) -> &'db OrderedHashMap<MacroCallId<'db>, ast::ItemInlineMacro<'db>> {
864 self.unnamed_items_data(db).macro_calls(db)
865 }
866
867 pub fn files(&self, db: &'db dyn Database) -> &'db Vec<FileId<'db>> {
869 self.files_data(db).files(db)
870 }
871
872 pub fn generated_file_aux_data(
874 &self,
875 db: &'db dyn Database,
876 ) -> &'db OrderedHashMap<FileId<'db>, Option<DynGeneratedFileAuxData>> {
877 self.files_data(db).generated_file_aux_data(db)
878 }
879
880 pub fn plugin_diagnostics(
881 &self,
882 db: &'db dyn Database,
883 ) -> &'db Vec<(ModuleId<'db>, PluginDiagnostic<'db>)> {
884 self.files_data(db).plugin_diagnostics(db)
885 }
886
887 pub fn diagnostics_notes(&self, db: &'db dyn Database) -> &'db PluginFileDiagnosticNotes<'db> {
891 self.files_data(db).diagnostics_notes(db)
892 }
893}
894
895#[derive(Clone, Debug, Eq, PartialEq, salsa::Update)]
897pub struct PrivModuleSubFiles<'db> {
898 files: OrderedHashMap<FileId<'db>, VirtualFile<'db>>,
900 aux_data: OrderedHashMap<FileId<'db>, Option<DynGeneratedFileAuxData>>,
902 items: Vec<ast::ModuleItem<'db>>,
904 plugin_diagnostics: Vec<PluginDiagnostic<'db>>,
906 diagnostics_notes: PluginFileDiagnosticNotes<'db>,
910}
911
912#[salsa::tracked]
913fn priv_module_data_helper<'db>(
914 db: &'db dyn Database,
915 _tracked: Tracked,
916 module_id: ModuleId<'db>,
917) -> Maybe<ModuleData<'db>> {
918 let crate_id = module_id.owning_crate(db);
919
920 if let Some((map, _)) = db.cached_crate_modules(crate_id) {
921 if let Some(module_data) = map.get(&module_id) {
922 return Ok(*module_data);
923 } else {
924 panic!("module not found in cached modules_data {:?}", module_id.name(db));
925 }
926 };
927
928 let module_file = db.module_main_file(module_id)?;
929 let main_file_aux_data = if let ModuleId::Submodule(submodule_id) = module_id {
930 let parent_module_data = submodule_id.module_data(db)?;
931 let item_module_ast = &parent_module_data.submodules(db)[&submodule_id];
932 if matches!(item_module_ast.body(db), MaybeModuleBody::Some(_)) {
933 parent_module_data.generated_file_aux_data(db)
940 [&item_module_ast.stable_ptr(db).untyped().file_id(db)]
941 .clone()
942 } else {
943 None
944 }
945 } else {
946 None
947 };
948 let mut file_queue = VecDeque::new();
949 file_queue.push_back(module_file);
950 let mut constants = OrderedHashMap::default();
951 let mut submodules = OrderedHashMap::default();
952 let mut uses = OrderedHashMap::default();
953 let mut free_functions = OrderedHashMap::default();
954 let mut structs = OrderedHashMap::default();
955 let mut enums = OrderedHashMap::default();
956 let mut type_aliases = OrderedHashMap::default();
957 let mut impl_aliases = OrderedHashMap::default();
958 let mut traits = OrderedHashMap::default();
959 let mut impls = OrderedHashMap::default();
960 let mut extern_types = OrderedHashMap::default();
961 let mut extern_functions = OrderedHashMap::default();
962 let mut macro_declarations = OrderedHashMap::default();
963 let mut macro_calls = OrderedHashMap::default();
964 let mut global_uses = OrderedHashMap::default();
965 let mut aux_data = OrderedHashMap::default();
966 let mut files = Vec::new();
967 let mut plugin_diagnostics = Vec::new();
968 let mut diagnostics_notes = OrderedHashMap::default();
969
970 let mut items = vec![];
971 aux_data.insert(module_file, main_file_aux_data);
972 while let Some(file_id) = file_queue.pop_front() {
973 files.push(file_id);
974
975 let priv_module_data = module_sub_files(db, module_id, file_id).maybe_as_ref()?;
976 diagnostics_notes.extend(priv_module_data.diagnostics_notes.clone().into_iter());
977 file_queue.extend(priv_module_data.files.keys().copied());
978 for diag in &priv_module_data.plugin_diagnostics {
979 plugin_diagnostics.push((module_id, diag.clone()));
980 }
981 aux_data.extend(
982 priv_module_data.aux_data.iter().map(|(file, aux_data)| (*file, aux_data.clone())),
983 );
984 for item_ast in &priv_module_data.items {
985 match item_ast.clone() {
986 ast::ModuleItem::Constant(constant) => {
987 let item_id = ConstantLongId(module_id, constant.stable_ptr(db)).intern(db);
988 constants.insert(item_id, constant);
989 items.push(ModuleItemId::Constant(item_id));
990 }
991 ast::ModuleItem::Module(module) => {
992 let item_id = SubmoduleLongId(module_id, module.stable_ptr(db)).intern(db);
993 submodules.insert(item_id, module);
994 items.push(ModuleItemId::Submodule(item_id));
995 }
996 ast::ModuleItem::Use(us) => {
997 for leaf in get_all_path_leaves(db, &us) {
998 let id = UseLongId(module_id, leaf.stable_ptr(db)).intern(db);
999 uses.insert(id, leaf);
1000 items.push(ModuleItemId::Use(id));
1001 }
1002 for star in get_all_path_stars(db, &us) {
1003 let id = GlobalUseLongId(module_id, star.stable_ptr(db)).intern(db);
1004 global_uses.insert(id, star);
1005 }
1006 }
1007 ast::ModuleItem::FreeFunction(function) => {
1008 let item_id = FreeFunctionLongId(module_id, function.stable_ptr(db)).intern(db);
1009 free_functions.insert(item_id, function);
1010 items.push(ModuleItemId::FreeFunction(item_id));
1011 }
1012 ast::ModuleItem::ExternFunction(extern_function) => {
1013 let item_id =
1014 ExternFunctionLongId(module_id, extern_function.stable_ptr(db)).intern(db);
1015 extern_functions.insert(item_id, extern_function);
1016 items.push(ModuleItemId::ExternFunction(item_id));
1017 }
1018 ast::ModuleItem::ExternType(extern_type) => {
1019 let item_id =
1020 ExternTypeLongId(module_id, extern_type.stable_ptr(db)).intern(db);
1021 extern_types.insert(item_id, extern_type);
1022 items.push(ModuleItemId::ExternType(item_id));
1023 }
1024 ast::ModuleItem::Trait(trt) => {
1025 let item_id = TraitLongId(module_id, trt.stable_ptr(db)).intern(db);
1026 traits.insert(item_id, trt);
1027 items.push(ModuleItemId::Trait(item_id));
1028 }
1029 ast::ModuleItem::Impl(imp) => {
1030 let item_id = ImplDefLongId(module_id, imp.stable_ptr(db)).intern(db);
1031 impls.insert(item_id, imp);
1032 items.push(ModuleItemId::Impl(item_id));
1033 }
1034 ast::ModuleItem::Struct(structure) => {
1035 let item_id = StructLongId(module_id, structure.stable_ptr(db)).intern(db);
1036 structs.insert(item_id, structure);
1037 items.push(ModuleItemId::Struct(item_id));
1038 }
1039 ast::ModuleItem::Enum(enm) => {
1040 let item_id = EnumLongId(module_id, enm.stable_ptr(db)).intern(db);
1041 enums.insert(item_id, enm);
1042 items.push(ModuleItemId::Enum(item_id));
1043 }
1044 ast::ModuleItem::TypeAlias(type_alias) => {
1045 let item_id =
1046 ModuleTypeAliasLongId(module_id, type_alias.stable_ptr(db)).intern(db);
1047 type_aliases.insert(item_id, type_alias);
1048 items.push(ModuleItemId::TypeAlias(item_id));
1049 }
1050 ast::ModuleItem::ImplAlias(impl_alias) => {
1051 let item_id = ImplAliasLongId(module_id, impl_alias.stable_ptr(db)).intern(db);
1052 impl_aliases.insert(item_id, impl_alias);
1053 items.push(ModuleItemId::ImplAlias(item_id));
1054 }
1055 ast::ModuleItem::MacroDeclaration(macro_declaration) => {
1056 let item_id =
1057 MacroDeclarationLongId(module_id, macro_declaration.stable_ptr(db))
1058 .intern(db);
1059 macro_declarations.insert(item_id, macro_declaration);
1060 items.push(ModuleItemId::MacroDeclaration(item_id));
1061 }
1062 ast::ModuleItem::InlineMacro(inline_macro_ast) => {
1063 let item_id =
1064 MacroCallLongId(module_id, inline_macro_ast.stable_ptr(db)).intern(db);
1065 macro_calls.insert(item_id, inline_macro_ast.clone());
1066 }
1067 ast::ModuleItem::HeaderDoc(_) => {}
1068 ast::ModuleItem::Missing(_) => {}
1069 }
1070 }
1071 }
1072 let types_data = ModuleTypesData::new(db, structs, enums, type_aliases, extern_types);
1073 let named_items_data = ModuleNamedItemsData::new(
1074 db,
1075 constants,
1076 submodules,
1077 uses,
1078 free_functions,
1079 impl_aliases,
1080 traits,
1081 impls,
1082 extern_functions,
1083 macro_declarations,
1084 );
1085 let unnamed_items_data = ModuleUnnamedItemsData::new(db, global_uses, macro_calls);
1086 let files_data =
1087 ModuleFilesData::new(db, files, aux_data, plugin_diagnostics, diagnostics_notes);
1088 Ok(ModuleData::new(db, items, types_data, named_items_data, unnamed_items_data, files_data))
1089}
1090
1091pub(crate) fn module_data<'db>(
1092 db: &'db dyn Database,
1093 module_id: ModuleId<'db>,
1094) -> Maybe<ModuleData<'db>> {
1095 priv_module_data_helper(db, (), module_id)
1096}
1097
1098pub type ModuleDataCacheAndLoadingData<'db> =
1099 (Arc<OrderedHashMap<ModuleId<'db>, ModuleData<'db>>>, Arc<DefCacheLoadingData<'db>>);
1100
1101#[salsa::tracked]
1102fn cached_crate_modules<'db>(
1103 db: &'db dyn Database,
1104 crate_id: CrateId<'db>,
1105) -> Option<ModuleDataCacheAndLoadingData<'db>> {
1106 load_cached_crate_modules(db, crate_id)
1107}
1108
1109pub fn init_external_files<T: DefsGroup>(db: &mut T) {
1110 let ext_as_virtual_impl: ExtAsVirtual =
1111 Arc::new(|db: &dyn Database, external_id: salsa::Id| ext_as_virtual_impl(db, external_id));
1112 files_group_input(db).set_ext_as_virtual_obj(db).to(Some(ext_as_virtual_impl));
1113}
1114
1115pub fn ext_as_virtual_impl<'db>(
1117 db: &'db dyn Database,
1118 external_id: salsa::Id,
1119) -> &'db VirtualFile<'db> {
1120 let long_id = PluginGeneratedFileId::from_intern_id(external_id).long(db);
1121 let file_id = FileLongId::External(external_id).intern(db);
1122 let data =
1123 module_sub_files(db, long_id.module_id, long_id.stable_ptr.file_id(db)).as_ref().unwrap();
1124 &data.files[&file_id]
1125}
1126
1127#[salsa::tracked(returns(ref))]
1128fn module_sub_files<'db>(
1130 db: &'db dyn Database,
1131 module_id: ModuleId<'db>,
1132 file_id: FileId<'db>,
1133) -> Maybe<PrivModuleSubFiles<'db>> {
1134 let module_main_file = db.module_main_file(module_id)?;
1135 let file_syntax = db.file_module_syntax(file_id)?;
1136 let item_asts = if module_main_file == file_id {
1137 if let ModuleId::Submodule(submodule_id) = module_id {
1138 let data = submodule_id.module_data(db)?;
1139 if let MaybeModuleBody::Some(body) = data.submodules(db)[&submodule_id].body(db) {
1140 Some(body.items(db))
1141 } else {
1142 None
1143 }
1144 } else {
1145 None
1146 }
1147 } else {
1148 None
1149 }
1150 .unwrap_or_else(|| file_syntax.items(db));
1151
1152 let crate_id = module_id.owning_crate(db);
1153
1154 let allowed_attributes = db.allowed_attributes(crate_id);
1155 let allowed_features = Default::default();
1157
1158 let cfg_set = db
1159 .crate_config(crate_id)
1160 .and_then(|cfg| cfg.settings.cfg_set.as_ref())
1161 .unwrap_or(db.cfg_set());
1162 let edition = db
1163 .crate_config(module_id.owning_crate(db))
1164 .map(|cfg| cfg.settings.edition)
1165 .unwrap_or_default();
1166 let metadata = MacroPluginMetadata {
1167 cfg_set,
1168 declared_derives: db.declared_derives(crate_id),
1169 allowed_features: &allowed_features,
1170 edition,
1171 };
1172
1173 let mut files = OrderedHashMap::<_, _>::default();
1174 let mut aux_data = OrderedHashMap::default();
1175 let mut items = Vec::new();
1176 let mut plugin_diagnostics = Vec::new();
1177 let mut diagnostics_notes = OrderedHashMap::default();
1178 for item_ast in item_asts.elements(db) {
1179 let mut remove_original_item = false;
1180 for plugin_id in db.crate_macro_plugins(crate_id).iter() {
1184 let plugin = plugin_id.long(db);
1185
1186 let result = plugin.generate_code(db, item_ast.clone(), &metadata);
1187 plugin_diagnostics.extend(result.diagnostics);
1188 if result.remove_original_item {
1189 remove_original_item = true;
1190 }
1191
1192 if let Some(generated) = result.code {
1193 let stable_ptr = item_ast.stable_ptr(db).untyped();
1194 let generated_file_id = FileLongId::External(
1195 PluginGeneratedFileLongId {
1196 module_id,
1197 stable_ptr,
1198 name: generated.name.clone(),
1199 }
1200 .intern(db)
1201 .as_intern_id(),
1202 )
1203 .intern(db);
1204 if let Some(text) = generated.diagnostics_note {
1205 diagnostics_notes
1206 .insert(generated_file_id, DiagnosticNote { text, location: None });
1207 }
1208 files.insert(
1209 generated_file_id,
1210 VirtualFile {
1211 parent: Some(stable_ptr.span_in_file(db)),
1212 name: SmolStrId::from(db, generated.name),
1213 content: SmolStrId::from(db, generated.content),
1214 code_mappings: generated.code_mappings.into(),
1215 kind: FileKind::Module,
1216 original_item_removed: remove_original_item,
1217 },
1218 );
1219 aux_data.insert(generated_file_id, generated.aux_data);
1220 }
1221 if remove_original_item {
1222 break;
1223 }
1224 }
1225 if remove_original_item {
1226 continue;
1228 }
1229 validate_attributes(db, allowed_attributes, &item_ast, &mut plugin_diagnostics);
1230 items.push(item_ast);
1231 }
1232 Ok(PrivModuleSubFiles { files, aux_data, items, plugin_diagnostics, diagnostics_notes })
1233}
1234
1235fn collect_extra_allowed_attributes<'db>(
1237 db: &'db dyn Database,
1238 item: &impl QueryAttrs<'db>,
1239 plugin_diagnostics: &mut Vec<PluginDiagnostic<'db>>,
1240) -> OrderedHashSet<SmolStrId<'db>> {
1241 let mut extra_allowed_attributes = OrderedHashSet::default();
1242 for attr in item.query_attr(db, ALLOW_ATTR_ATTR) {
1243 let args = attr.clone().structurize(db).args;
1244 if args.is_empty() {
1245 plugin_diagnostics.push(PluginDiagnostic::error(
1246 attr.stable_ptr(db),
1247 "Expected arguments.".to_string(),
1248 ));
1249 continue;
1250 }
1251 for arg in args {
1252 if let Some(ast::Expr::Path(path)) = try_extract_unnamed_arg(db, &arg.arg)
1253 && let Some([ast::PathSegment::Simple(segment)]) =
1254 path.segments(db).elements(db).collect_array()
1255 {
1256 extra_allowed_attributes.insert(segment.ident(db).text(db));
1257 continue;
1258 }
1259 plugin_diagnostics.push(PluginDiagnostic::error(
1260 arg.arg.stable_ptr(db),
1261 "Expected simple identifier.".to_string(),
1262 ));
1263 }
1264 }
1265 extra_allowed_attributes
1266}
1267
1268pub fn validate_attributes_flat<'db, Item: QueryAttrs<'db> + TypedSyntaxNode<'db>>(
1270 db: &'db dyn Database,
1271 allowed_attributes: &OrderedHashSet<SmolStrId<'db>>,
1272 extra_allowed_attributes: &OrderedHashSet<SmolStrId<'db>>,
1273 item: &Item,
1274 plugin_diagnostics: &mut Vec<PluginDiagnostic<'db>>,
1275) {
1276 let local_extra_attributes = collect_extra_allowed_attributes(db, item, plugin_diagnostics);
1277 for attr in item.attributes_elements(db) {
1278 let attr_text = attr.attr(db).as_syntax_node().get_text_without_trivia(db);
1279 if !(allowed_attributes.contains(&attr_text)
1280 || extra_allowed_attributes.contains(&attr_text)
1281 || local_extra_attributes.contains(&attr_text))
1282 {
1283 plugin_diagnostics.push(PluginDiagnostic::error(
1284 attr.stable_ptr(db),
1285 "Unsupported attribute.".to_string(),
1286 ));
1287 }
1288 }
1289
1290 for attr in item.query_attr(db, PATH_ATTR) {
1292 let node = item.as_syntax_node();
1293 let Some(item_module) = ast::ItemModule::cast(db, node) else {
1294 plugin_diagnostics.push(PluginDiagnostic::error(
1295 attr.stable_ptr(db),
1296 "`#[path(..)]` is only allowed on module declarations.".to_string(),
1297 ));
1298 continue;
1299 };
1300 if matches!(item_module.body(db), MaybeModuleBody::Some(_)) {
1302 plugin_diagnostics.push(PluginDiagnostic::error(
1303 attr.stable_ptr(db),
1304 "`#[path(..)]` requires a file-based module: use `mod name;` with a semicolon."
1305 .to_string(),
1306 ));
1307 continue;
1308 }
1309
1310 let args = attr.arguments(db);
1311 if extract_path_arg(db, &args).is_none() {
1312 plugin_diagnostics.push(PluginDiagnostic::error(
1313 args.stable_ptr(db),
1314 "`#[path(..)]` expects exactly one string literal argument.".to_string(),
1315 ));
1316 }
1317 }
1318}
1319
1320fn extract_path_arg<'db>(
1322 db: &'db dyn Database,
1323 args: &ast::OptionArgListParenthesized<'db>,
1324) -> Option<ast::TerminalString<'db>> {
1325 match args {
1326 ast::OptionArgListParenthesized::Empty(_) => None,
1327 ast::OptionArgListParenthesized::ArgListParenthesized(args) => {
1328 let [arg] = args.arguments(db).elements(db).collect_array()?;
1329 if let ast::Expr::String(path) = try_extract_unnamed_arg(db, &arg)? {
1330 Some(path)
1331 } else {
1332 None
1333 }
1334 }
1335 }
1336}
1337
1338fn validate_attributes_element_list<'db, Item: QueryAttrs<'db> + TypedSyntaxNode<'db>>(
1341 db: &'db dyn Database,
1342 allowed_attributes: &OrderedHashSet<SmolStrId<'db>>,
1343 extra_allowed_attributes: &OrderedHashSet<SmolStrId<'db>>,
1344 items: impl Iterator<Item = Item>,
1345 plugin_diagnostics: &mut Vec<PluginDiagnostic<'db>>,
1346) {
1347 for item in items {
1348 validate_attributes_flat(
1349 db,
1350 allowed_attributes,
1351 extra_allowed_attributes,
1352 &item,
1353 plugin_diagnostics,
1354 );
1355 }
1356}
1357
1358fn validate_attributes<'db>(
1361 db: &'db dyn Database,
1362 allowed_attributes: &OrderedHashSet<SmolStrId<'db>>,
1363 item_ast: &ast::ModuleItem<'db>,
1364 plugin_diagnostics: &mut Vec<PluginDiagnostic<'db>>,
1365) {
1366 let extra_allowed_attributes =
1367 collect_extra_allowed_attributes(db, item_ast, plugin_diagnostics);
1368 validate_attributes_flat(
1369 db,
1370 allowed_attributes,
1371 &extra_allowed_attributes,
1372 item_ast,
1373 plugin_diagnostics,
1374 );
1375
1376 match item_ast {
1377 ast::ModuleItem::Trait(item) => {
1378 if let ast::MaybeTraitBody::Some(body) = item.body(db) {
1379 validate_attributes_element_list(
1380 db,
1381 allowed_attributes,
1382 &extra_allowed_attributes,
1383 body.items(db).elements(db),
1384 plugin_diagnostics,
1385 );
1386 }
1387 }
1388 ast::ModuleItem::Impl(item) => {
1389 if let ast::MaybeImplBody::Some(body) = item.body(db) {
1390 validate_attributes_element_list(
1391 db,
1392 allowed_attributes,
1393 &extra_allowed_attributes,
1394 body.items(db).elements(db),
1395 plugin_diagnostics,
1396 );
1397 }
1398 }
1399 ast::ModuleItem::Struct(item) => {
1400 validate_attributes_element_list(
1401 db,
1402 allowed_attributes,
1403 &extra_allowed_attributes,
1404 item.members(db).elements(db),
1405 plugin_diagnostics,
1406 );
1407 }
1408 ast::ModuleItem::Enum(item) => {
1409 validate_attributes_element_list(
1410 db,
1411 allowed_attributes,
1412 &extra_allowed_attributes,
1413 item.variants(db).elements(db),
1414 plugin_diagnostics,
1415 );
1416 }
1417 _ => {}
1418 }
1419}
1420
1421pub fn get_all_path_leaves<'db>(
1423 db: &'db dyn Database,
1424 use_item: &ast::ItemUse<'db>,
1425) -> Vec<ast::UsePathLeaf<'db>> {
1426 let mut res = vec![];
1427 let mut stack = vec![use_item.use_path(db)];
1428 while let Some(use_path) = stack.pop() {
1429 match use_path {
1430 ast::UsePath::Leaf(use_path) => res.push(use_path),
1431 ast::UsePath::Single(use_path) => stack.push(use_path.use_path(db)),
1432 ast::UsePath::Multi(use_path) => {
1433 stack.extend(use_path.use_paths(db).elements(db).rev())
1434 }
1435 ast::UsePath::Star(_) => {}
1436 }
1437 }
1438 res
1439}
1440
1441pub fn get_all_path_stars<'db>(
1443 db: &'db dyn Database,
1444 use_item: &ast::ItemUse<'db>,
1445) -> Vec<ast::UsePathStar<'db>> {
1446 let mut res = vec![];
1447 let mut stack = vec![use_item.use_path(db)];
1448 while let Some(use_path) = stack.pop() {
1449 match use_path {
1450 ast::UsePath::Leaf(_) => {}
1451 ast::UsePath::Single(use_path) => stack.push(use_path.use_path(db)),
1452 ast::UsePath::Multi(use_path) => {
1453 stack.extend(use_path.use_paths(db).elements(db).rev())
1454 }
1455 ast::UsePath::Star(use_path) => res.push(use_path),
1456 }
1457 }
1458 res
1459}
1460
1461#[salsa::tracked(returns(ref))]
1462fn module_constants_ids_helper<'db>(
1463 db: &'db dyn Database,
1464 module_data: ModuleData<'db>,
1465) -> Vec<ConstantId<'db>> {
1466 module_data.constants(db).keys().copied().collect_vec()
1467}
1468
1469pub fn module_constants_ids<'db>(
1470 db: &'db dyn Database,
1471 module_id: ModuleId<'db>,
1472) -> Maybe<&'db [ConstantId<'db>]> {
1473 Ok(module_constants_ids_helper(db, module_id.module_data(db)?))
1474}
1475
1476#[salsa::tracked]
1477pub fn module_constant_by_id<'db>(
1478 db: &'db dyn Database,
1479 constant_id: ConstantId<'db>,
1480) -> Maybe<ast::ItemConstant<'db>> {
1481 let module_constants = constant_id.module_data(db)?.constants(db);
1482 module_constants.get(&constant_id).cloned().ok_or_else(skip_diagnostic)
1483}
1484
1485#[salsa::tracked(returns(ref))]
1486fn module_submodules_ids_helper<'db>(
1487 db: &'db dyn Database,
1488 module_data: ModuleData<'db>,
1489) -> Vec<SubmoduleId<'db>> {
1490 module_data.submodules(db).keys().copied().collect_vec()
1491}
1492
1493fn module_submodules_ids<'db>(
1494 db: &'db dyn Database,
1495 module_id: ModuleId<'db>,
1496) -> Maybe<&'db [SubmoduleId<'db>]> {
1497 Ok(module_submodules_ids_helper(db, module_id.module_data(db)?))
1498}
1499
1500#[salsa::tracked]
1501pub fn module_submodule_by_id<'db>(
1502 db: &'db dyn Database,
1503 submodule_id: SubmoduleId<'db>,
1504) -> Maybe<ast::ItemModule<'db>> {
1505 let module_submodules = submodule_id.module_data(db)?.submodules(db);
1506 module_submodules.get(&submodule_id).cloned().ok_or_else(skip_diagnostic)
1507}
1508
1509#[salsa::tracked(returns(ref))]
1510fn module_free_functions_ids_helper<'db>(
1511 db: &'db dyn Database,
1512 module_data: ModuleData<'db>,
1513) -> Vec<FreeFunctionId<'db>> {
1514 module_data.free_functions(db).keys().copied().collect_vec()
1515}
1516
1517pub fn module_free_functions_ids<'db>(
1518 db: &'db dyn Database,
1519 module_id: ModuleId<'db>,
1520) -> Maybe<&'db [FreeFunctionId<'db>]> {
1521 Ok(module_free_functions_ids_helper(db, module_id.module_data(db)?))
1522}
1523
1524#[salsa::tracked]
1525pub fn module_free_function_by_id<'db>(
1526 db: &'db dyn Database,
1527 free_function_id: FreeFunctionId<'db>,
1528) -> Maybe<ast::FunctionWithBody<'db>> {
1529 let module_free_functions = free_function_id.module_data(db)?.free_functions(db);
1530 module_free_functions.get(&free_function_id).cloned().ok_or_else(skip_diagnostic)
1531}
1532
1533#[salsa::tracked(returns(ref))]
1534fn module_uses_ids_helper<'db>(
1535 db: &'db dyn Database,
1536 module_data: ModuleData<'db>,
1537) -> Vec<UseId<'db>> {
1538 module_data.uses(db).keys().copied().collect_vec()
1539}
1540pub fn module_uses_ids<'db>(
1541 db: &'db dyn Database,
1542 module_id: ModuleId<'db>,
1543) -> Maybe<&'db [UseId<'db>]> {
1544 Ok(module_uses_ids_helper(db, module_id.module_data(db)?))
1545}
1546
1547#[salsa::tracked]
1548pub fn module_use_by_id<'db>(
1549 db: &'db dyn Database,
1550 use_id: UseId<'db>,
1551) -> Maybe<ast::UsePathLeaf<'db>> {
1552 let module_uses = use_id.module_data(db)?.uses(db);
1553 module_uses.get(&use_id).cloned().ok_or_else(skip_diagnostic)
1554}
1555
1556#[salsa::tracked]
1558pub fn module_global_use_by_id<'db>(
1559 db: &'db dyn Database,
1560 global_use_id: GlobalUseId<'db>,
1561) -> Maybe<ast::UsePathStar<'db>> {
1562 let module_global_uses = global_use_id.module_data(db)?.global_uses(db);
1563 module_global_uses.get(&global_use_id).cloned().ok_or_else(skip_diagnostic)
1564}
1565
1566#[salsa::tracked(returns(ref))]
1567fn module_structs_ids_helper<'db>(
1568 db: &'db dyn Database,
1569 module_data: ModuleData<'db>,
1570) -> Vec<StructId<'db>> {
1571 module_data.structs(db).keys().copied().collect_vec()
1572}
1573
1574pub fn module_structs_ids<'db>(
1575 db: &'db dyn Database,
1576 module_id: ModuleId<'db>,
1577) -> Maybe<&'db [StructId<'db>]> {
1578 Ok(module_structs_ids_helper(db, module_id.module_data(db)?))
1579}
1580
1581#[salsa::tracked]
1582pub fn module_struct_by_id<'db>(
1583 db: &'db dyn Database,
1584 struct_id: StructId<'db>,
1585) -> Maybe<ast::ItemStruct<'db>> {
1586 let module_structs = struct_id.module_data(db)?.structs(db);
1587 module_structs.get(&struct_id).cloned().ok_or_else(skip_diagnostic)
1588}
1589
1590#[salsa::tracked(returns(ref))]
1591fn module_enums_ids_helper<'db>(
1592 db: &'db dyn Database,
1593 module_data: ModuleData<'db>,
1594) -> Vec<EnumId<'db>> {
1595 module_data.enums(db).keys().copied().collect_vec()
1596}
1597
1598pub fn module_enums_ids<'db>(
1599 db: &'db dyn Database,
1600 module_id: ModuleId<'db>,
1601) -> Maybe<&'db [EnumId<'db>]> {
1602 Ok(module_enums_ids_helper(db, module_id.module_data(db)?))
1603}
1604
1605#[salsa::tracked]
1606pub fn module_enum_by_id<'db>(
1607 db: &'db dyn Database,
1608 enum_id: EnumId<'db>,
1609) -> Maybe<ast::ItemEnum<'db>> {
1610 let module_enums = enum_id.module_data(db)?.enums(db);
1611 module_enums.get(&enum_id).cloned().ok_or_else(skip_diagnostic)
1612}
1613
1614#[salsa::tracked(returns(ref))]
1615fn module_type_aliases_ids_helper<'db>(
1616 db: &'db dyn Database,
1617 module_data: ModuleData<'db>,
1618) -> Vec<ModuleTypeAliasId<'db>> {
1619 module_data.type_aliases(db).keys().copied().collect_vec()
1620}
1621
1622pub fn module_type_aliases_ids<'db>(
1623 db: &'db dyn Database,
1624 module_id: ModuleId<'db>,
1625) -> Maybe<&'db [ModuleTypeAliasId<'db>]> {
1626 Ok(module_type_aliases_ids_helper(db, module_id.module_data(db)?))
1627}
1628
1629#[salsa::tracked]
1630pub fn module_type_alias_by_id<'db>(
1631 db: &'db dyn Database,
1632 module_type_alias_id: ModuleTypeAliasId<'db>,
1633) -> Maybe<ast::ItemTypeAlias<'db>> {
1634 let module_type_aliases = module_type_alias_id.module_data(db)?.type_aliases(db);
1635 module_type_aliases.get(&module_type_alias_id).cloned().ok_or_else(skip_diagnostic)
1636}
1637
1638#[salsa::tracked(returns(ref))]
1639fn module_impl_aliases_ids_helper<'db>(
1640 db: &'db dyn Database,
1641 module_data: ModuleData<'db>,
1642) -> Vec<ImplAliasId<'db>> {
1643 module_data.impl_aliases(db).keys().copied().collect_vec()
1644}
1645
1646pub fn module_impl_aliases_ids<'db>(
1647 db: &'db dyn Database,
1648 module_id: ModuleId<'db>,
1649) -> Maybe<&'db [ImplAliasId<'db>]> {
1650 Ok(module_impl_aliases_ids_helper(db, module_id.module_data(db)?))
1651}
1652
1653#[salsa::tracked]
1654pub fn module_impl_alias_by_id<'db>(
1655 db: &'db dyn Database,
1656 impl_alias_id: ImplAliasId<'db>,
1657) -> Maybe<ast::ItemImplAlias<'db>> {
1658 let module_impl_aliases = impl_alias_id.module_data(db)?.impl_aliases(db);
1659 module_impl_aliases.get(&impl_alias_id).cloned().ok_or_else(skip_diagnostic)
1660}
1661
1662#[salsa::tracked(returns(ref))]
1663fn module_traits_ids_helper<'db>(
1664 db: &'db dyn Database,
1665 module_data: ModuleData<'db>,
1666) -> Vec<TraitId<'db>> {
1667 module_data.traits(db).keys().copied().collect_vec()
1668}
1669
1670pub fn module_traits_ids<'db>(
1671 db: &'db dyn Database,
1672 module_id: ModuleId<'db>,
1673) -> Maybe<&'db [TraitId<'db>]> {
1674 Ok(module_traits_ids_helper(db, module_id.module_data(db)?))
1675}
1676
1677#[salsa::tracked]
1678pub fn module_trait_by_id<'db>(
1679 db: &'db dyn Database,
1680 trait_id: TraitId<'db>,
1681) -> Maybe<ast::ItemTrait<'db>> {
1682 let module_traits = trait_id.module_data(db)?.traits(db);
1683 module_traits.get(&trait_id).cloned().ok_or_else(skip_diagnostic)
1684}
1685
1686#[salsa::tracked(returns(ref))]
1687fn module_impls_ids_helper<'db>(
1688 db: &'db dyn Database,
1689 module_data: ModuleData<'db>,
1690) -> Vec<ImplDefId<'db>> {
1691 module_data.impls(db).keys().copied().collect_vec()
1692}
1693
1694pub fn module_impls_ids<'db>(
1695 db: &'db dyn Database,
1696 module_id: ModuleId<'db>,
1697) -> Maybe<&'db [ImplDefId<'db>]> {
1698 Ok(module_impls_ids_helper(db, module_id.module_data(db)?))
1699}
1700
1701#[salsa::tracked]
1702pub fn module_impl_by_id<'db>(
1703 db: &'db dyn Database,
1704 impl_def_id: ImplDefId<'db>,
1705) -> Maybe<ast::ItemImpl<'db>> {
1706 let module_impls = impl_def_id.module_data(db)?.impls(db);
1707 module_impls.get(&impl_def_id).cloned().ok_or_else(skip_diagnostic)
1708}
1709
1710#[salsa::tracked(returns(ref))]
1711fn module_extern_types_ids_helper<'db>(
1712 db: &'db dyn Database,
1713 module_data: ModuleData<'db>,
1714) -> Vec<ExternTypeId<'db>> {
1715 module_data.extern_types(db).keys().copied().collect_vec()
1716}
1717pub fn module_extern_types_ids<'db>(
1718 db: &'db dyn Database,
1719 module_id: ModuleId<'db>,
1720) -> Maybe<&'db [ExternTypeId<'db>]> {
1721 Ok(module_extern_types_ids_helper(db, module_id.module_data(db)?))
1722}
1723
1724#[salsa::tracked]
1725pub fn module_extern_type_by_id<'db>(
1726 db: &'db dyn Database,
1727 extern_type_id: ExternTypeId<'db>,
1728) -> Maybe<ast::ItemExternType<'db>> {
1729 let module_extern_types = extern_type_id.module_data(db)?.extern_types(db);
1730 module_extern_types.get(&extern_type_id).cloned().ok_or_else(skip_diagnostic)
1731}
1732
1733#[salsa::tracked(returns(ref))]
1734fn module_macro_declarations_ids_helper<'db>(
1735 db: &'db dyn Database,
1736 module_data: ModuleData<'db>,
1737) -> Vec<MacroDeclarationId<'db>> {
1738 module_data.macro_declarations(db).keys().copied().collect_vec()
1739}
1740
1741pub fn module_macro_declarations_ids<'db>(
1743 db: &'db dyn Database,
1744 module_id: ModuleId<'db>,
1745) -> Maybe<&'db [MacroDeclarationId<'db>]> {
1746 Ok(module_macro_declarations_ids_helper(db, module_id.module_data(db)?))
1747}
1748
1749#[salsa::tracked]
1751pub fn module_macro_declaration_by_id<'db>(
1752 db: &'db dyn Database,
1753 macro_declaration_id: MacroDeclarationId<'db>,
1754) -> Maybe<ast::ItemMacroDeclaration<'db>> {
1755 let module_macro_declarations = macro_declaration_id.module_data(db)?.macro_declarations(db);
1756 module_macro_declarations.get(¯o_declaration_id).cloned().ok_or_else(skip_diagnostic)
1757}
1758
1759#[salsa::tracked(returns(ref))]
1760fn module_macro_calls_ids_helper<'db>(
1761 db: &'db dyn Database,
1762 module_data: ModuleData<'db>,
1763) -> Vec<MacroCallId<'db>> {
1764 module_data.macro_calls(db).keys().copied().collect_vec()
1765}
1766
1767pub fn module_macro_calls_ids<'db>(
1768 db: &'db dyn Database,
1769 module_id: ModuleId<'db>,
1770) -> Maybe<&'db [MacroCallId<'db>]> {
1771 Ok(module_macro_calls_ids_helper(db, module_id.module_data(db)?))
1772}
1773
1774#[salsa::tracked]
1775fn module_macro_call_by_id<'db>(
1776 db: &'db dyn Database,
1777 macro_call_id: MacroCallId<'db>,
1778) -> Maybe<ast::ItemInlineMacro<'db>> {
1779 let module_macro_calls = macro_call_id.module_data(db)?.macro_calls(db);
1780 module_macro_calls.get(¯o_call_id).cloned().ok_or_else(skip_diagnostic)
1781}
1782
1783#[salsa::tracked(returns(ref))]
1784fn module_extern_functions_ids_helper<'db>(
1785 db: &'db dyn Database,
1786 module_data: ModuleData<'db>,
1787) -> Vec<ExternFunctionId<'db>> {
1788 module_data.extern_functions(db).keys().copied().collect_vec()
1789}
1790
1791pub fn module_extern_functions_ids<'db>(
1792 db: &'db dyn Database,
1793 module_id: ModuleId<'db>,
1794) -> Maybe<&'db [ExternFunctionId<'db>]> {
1795 Ok(module_extern_functions_ids_helper(db, module_id.module_data(db)?))
1796}
1797
1798#[salsa::tracked]
1799pub fn module_extern_function_by_id<'db>(
1800 db: &'db dyn Database,
1801 extern_function_id: ExternFunctionId<'db>,
1802) -> Maybe<ast::ItemExternFunction<'db>> {
1803 let module_extern_functions = extern_function_id.module_data(db)?.extern_functions(db);
1804 module_extern_functions.get(&extern_function_id).cloned().ok_or_else(skip_diagnostic)
1805}
1806
1807#[salsa::tracked(returns(ref))]
1808fn module_ancestors_helper<'db>(
1809 db: &'db dyn Database,
1810 _tracked: Tracked,
1811 module_id: ModuleId<'db>,
1812) -> OrderedHashSet<ModuleId<'db>> {
1813 let mut current = module_id;
1814 let mut ancestors = OrderedHashSet::default();
1815 loop {
1816 match current {
1817 ModuleId::CrateRoot(_) => {
1818 ancestors.insert(current);
1819 return ancestors;
1820 }
1821 ModuleId::Submodule(submodule_id) => {
1822 ancestors.insert(current);
1823 current = submodule_id.parent_module(db);
1824 }
1825 ModuleId::MacroCall { id, .. } => {
1826 current = id.parent_module(db);
1827 }
1828 }
1829 }
1830}
1831
1832#[salsa::tracked]
1833fn module_perceived_module_helper<'db>(
1834 db: &'db dyn Database,
1835 _tracked: Tracked,
1836 mut module_id: ModuleId<'db>,
1837) -> ModuleId<'db> {
1838 while let ModuleId::MacroCall { id, .. } = module_id {
1839 module_id = id.parent_module(db);
1840 }
1841 module_id
1842}
1843
1844fn module_item_name_stable_ptr<'db>(
1845 db: &'db dyn Database,
1846 module_id: ModuleId<'db>,
1847 item_id: ModuleItemId<'db>,
1848) -> Maybe<SyntaxStablePtrId<'db>> {
1849 let data = module_id.module_data(db)?;
1850 Ok(match &item_id {
1851 ModuleItemId::Constant(id) => data.constants(db)[id].name(db).stable_ptr(db).untyped(),
1852 ModuleItemId::Submodule(id) => data.submodules(db)[id].name(db).stable_ptr(db).untyped(),
1853 ModuleItemId::Use(id) => data.uses(db)[id].name_stable_ptr(db),
1854 ModuleItemId::FreeFunction(id) => {
1855 data.free_functions(db)[id].declaration(db).name(db).stable_ptr(db).untyped()
1856 }
1857 ModuleItemId::Struct(id) => data.structs(db)[id].name(db).stable_ptr(db).untyped(),
1858 ModuleItemId::Enum(id) => data.enums(db)[id].name(db).stable_ptr(db).untyped(),
1859 ModuleItemId::TypeAlias(id) => data.type_aliases(db)[id].name(db).stable_ptr(db).untyped(),
1860 ModuleItemId::ImplAlias(id) => data.impl_aliases(db)[id].name(db).stable_ptr(db).untyped(),
1861 ModuleItemId::Trait(id) => data.traits(db)[id].name(db).stable_ptr(db).untyped(),
1862 ModuleItemId::Impl(id) => data.impls(db)[id].name(db).stable_ptr(db).untyped(),
1863 ModuleItemId::ExternType(id) => data.extern_types(db)[id].name(db).stable_ptr(db).untyped(),
1864 ModuleItemId::ExternFunction(id) => {
1865 data.extern_functions(db)[id].declaration(db).name(db).stable_ptr(db).untyped()
1866 }
1867 ModuleItemId::MacroDeclaration(id) => {
1868 data.macro_declarations(db)[id].name(db).stable_ptr(db).untyped()
1869 }
1870 })
1871}
1872
1873pub trait DefsGroupEx: DefsGroup {
1874 fn set_override_crate_macro_plugins<'db>(
1878 &mut self,
1879 crate_id: CrateId<'db>,
1880 plugins: Arc<Vec<MacroPluginId<'db>>>,
1881 ) {
1882 let crate_input = self.crate_input(crate_id);
1883 let mut overrides = self.macro_plugin_overrides_input().clone();
1884 let plugins = plugins.iter().map(|plugin| plugin.long(self).clone()).collect();
1885 overrides.insert(crate_input.clone(), plugins);
1886 defs_group_input(self.as_dyn_database())
1887 .set_macro_plugin_overrides(self)
1888 .to(Some(overrides));
1889 }
1890
1891 fn set_override_crate_inline_macro_plugins<'db>(
1895 &mut self,
1896 crate_id: CrateId<'db>,
1897 plugins: Arc<OrderedHashMap<String, InlineMacroExprPluginId<'db>>>,
1898 ) {
1899 let crate_input = self.crate_input(crate_id);
1900 let mut overrides = self.inline_macro_plugin_overrides_input().clone();
1901 let plugins = Arc::new(
1902 plugins
1903 .iter()
1904 .map(|(name, plugin)| (name.clone(), plugin.long(self).clone()))
1905 .collect(),
1906 );
1907 overrides.insert(crate_input.clone(), plugins);
1908 defs_group_input(self.as_dyn_database())
1909 .set_inline_macro_plugin_overrides(self)
1910 .to(Some(overrides));
1911 }
1912}
1913
1914impl<T: DefsGroup + ?Sized> DefsGroupEx for T {}