1use std::sync::Arc;
2
3use cairo_lang_defs::db::{DefsGroup, DefsGroupEx, defs_group_input};
4use cairo_lang_defs::ids::{
5 ImplAliasId, InlineMacroExprPluginId, InlineMacroExprPluginLongId, LanguageElementId,
6 LookupItemId, MacroPluginId, MacroPluginLongId, ModuleId, ModuleItemId, UseId,
7};
8use cairo_lang_diagnostics::{Diagnostics, DiagnosticsBuilder, Maybe};
9use cairo_lang_filesystem::db::FilesGroup;
10use cairo_lang_filesystem::ids::{CrateId, CrateInput, FileId, FileLongId, SmolStrId, Tracked};
11use cairo_lang_syntax::attribute::consts::{DEPRECATED_ATTR, UNUSED_IMPORTS, UNUSED_VARIABLES};
12use cairo_lang_syntax::node::{TypedStablePtr, ast};
13use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
14use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
15use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
16use cairo_lang_utils::{Intern, require};
17use itertools::{Itertools, chain};
18use salsa::{Database, Setter};
19
20use crate::SemanticDiagnostic;
21use crate::cache::{SemanticCacheLoadingData, load_cached_crate_modules_semantic};
22use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder};
23use crate::ids::{AnalyzerPluginId, AnalyzerPluginLongId};
24use crate::items::constant::ConstantSemantic;
25use crate::items::enm::EnumSemantic;
26use crate::items::extern_function::ExternFunctionSemantic;
27use crate::items::extern_type::ExternTypeSemantic;
28use crate::items::free_function::FreeFunctionSemantic;
29use crate::items::imp::{ImplId, ImplSemantic};
30use crate::items::impl_alias::ImplAliasSemantic;
31use crate::items::macro_call::{MacroCallSemantic, module_macro_modules};
32use crate::items::macro_declaration::MacroDeclarationSemantic;
33use crate::items::module::{ModuleSemantic, ModuleSemanticData};
34use crate::items::module_type_alias::ModuleTypeAliasSemantic;
35use crate::items::structure::StructSemantic;
36use crate::items::trt::TraitSemantic;
37use crate::items::us::{SemanticUseEx, UseSemantic};
38use crate::items::visibility::Visibility;
39use crate::plugin::{AnalyzerPlugin, InternedPluginSuite, PluginSuite};
40use crate::resolve::{ResolvedConcreteItem, ResolvedGenericItem, ResolverData};
41
42#[salsa::input]
43pub struct SemanticGroupInput {
44 #[returns(ref)]
45 pub default_analyzer_plugins: Option<Vec<AnalyzerPluginLongId>>,
46 #[returns(ref)]
47 pub analyzer_plugin_overrides: Option<OrderedHashMap<CrateInput, Arc<[AnalyzerPluginLongId]>>>,
48}
49
50#[salsa::tracked(returns(ref))]
51pub fn semantic_group_input(db: &dyn Database) -> SemanticGroupInput {
52 SemanticGroupInput::new(db, None, None)
53}
54
55fn default_analyzer_plugins_input(db: &dyn Database) -> &[AnalyzerPluginLongId] {
56 semantic_group_input(db).default_analyzer_plugins(db).as_ref().unwrap()
57}
58
59fn analyzer_plugin_overrides_input(
60 db: &dyn Database,
61) -> &OrderedHashMap<CrateInput, Arc<[AnalyzerPluginLongId]>> {
62 semantic_group_input(db).analyzer_plugin_overrides(db).as_ref().unwrap()
63}
64
65pub trait SemanticGroup: Database {
72 fn lookup_resolved_generic_item_by_ptr<'db>(
75 &'db self,
76 id: LookupItemId<'db>,
77 ptr: ast::TerminalIdentifierPtr<'db>,
78 ) -> Option<ResolvedGenericItem<'db>> {
79 lookup_resolved_generic_item_by_ptr(self.as_dyn_database(), id, ptr)
80 }
81
82 fn lookup_resolved_concrete_item_by_ptr<'db>(
83 &'db self,
84 id: LookupItemId<'db>,
85 ptr: ast::TerminalIdentifierPtr<'db>,
86 ) -> Option<ResolvedConcreteItem<'db>> {
87 lookup_resolved_concrete_item_by_ptr(self.as_dyn_database(), id, ptr)
88 }
89
90 fn module_semantic_diagnostics<'db>(
94 &'db self,
95 module_id: ModuleId<'db>,
96 ) -> Maybe<Diagnostics<'db, SemanticDiagnostic<'db>>> {
97 module_semantic_diagnostics_tracked(self.as_dyn_database(), (), module_id)
98 }
99
100 fn file_semantic_diagnostics<'db>(
102 &'db self,
103 file_id: FileId<'db>,
104 ) -> Maybe<Diagnostics<'db, SemanticDiagnostic<'db>>> {
105 file_semantic_diagnostics(self.as_dyn_database(), file_id)
106 }
107
108 fn default_analyzer_plugins_input(&self) -> &[AnalyzerPluginLongId] {
111 default_analyzer_plugins_input(self.as_dyn_database())
112 }
113
114 fn default_analyzer_plugins<'db>(&'db self) -> Arc<Vec<AnalyzerPluginId<'db>>> {
116 default_analyzer_plugins(self.as_dyn_database())
117 }
118
119 fn analyzer_plugin_overrides_input(
120 &self,
121 ) -> &OrderedHashMap<CrateInput, Arc<[AnalyzerPluginLongId]>> {
122 analyzer_plugin_overrides_input(self.as_dyn_database())
123 }
124
125 fn analyzer_plugin_overrides<'db>(
127 &'db self,
128 ) -> Arc<OrderedHashMap<CrateId<'db>, Arc<Vec<AnalyzerPluginId<'db>>>>> {
129 analyzer_plugin_overrides(self.as_dyn_database())
130 }
131
132 fn crate_analyzer_plugins<'db>(
137 &'db self,
138 crate_id: CrateId<'db>,
139 ) -> Arc<Vec<AnalyzerPluginId<'db>>> {
140 crate_analyzer_plugins(self.as_dyn_database(), crate_id)
141 }
142
143 fn declared_allows<'db>(&self, crate_id: CrateId<'db>) -> Arc<OrderedHashSet<String>> {
146 declared_allows(self.as_dyn_database(), crate_id)
147 }
148
149 fn cached_crate_semantic_data<'db>(
152 &'db self,
153 crate_id: CrateId<'db>,
154 ) -> Option<ModuleSemanticDataCacheAndLoadingData<'db>> {
155 cached_crate_semantic_data(self.as_dyn_database(), crate_id)
156 }
157}
158
159impl<T: Database + ?Sized> SemanticGroup for T {}
160
161pub fn init_semantic_group(db: &mut dyn Database) {
163 semantic_group_input(db).set_analyzer_plugin_overrides(db).to(Some(OrderedHashMap::default()));
164}
165
166#[salsa::tracked]
167fn default_analyzer_plugins(db: &dyn Database) -> Arc<Vec<AnalyzerPluginId<'_>>> {
168 let inp = db.default_analyzer_plugins_input();
169 Arc::new(inp.iter().map(|plugin| plugin.clone().intern(db)).collect_vec())
170}
171
172#[salsa::tracked]
173fn analyzer_plugin_overrides(
174 db: &dyn Database,
175) -> Arc<OrderedHashMap<CrateId<'_>, Arc<Vec<AnalyzerPluginId<'_>>>>> {
176 let inp = db.analyzer_plugin_overrides_input();
177 Arc::new(
178 inp.iter()
179 .map(|(crate_input, plugins)| {
180 (
181 crate_input.clone().into_crate_long_id(db).intern(db),
182 Arc::new(plugins.iter().map(|plugin| plugin.clone().intern(db)).collect_vec()),
183 )
184 })
185 .collect(),
186 )
187}
188
189#[salsa::tracked]
190fn module_semantic_diagnostics_tracked<'db>(
191 db: &'db dyn Database,
192 _tracked: Tracked,
193 module_id: ModuleId<'db>,
194) -> Maybe<Diagnostics<'db, SemanticDiagnostic<'db>>> {
195 module_semantic_diagnostics(db, module_id)
196}
197
198fn module_semantic_diagnostics<'db>(
199 db: &'db dyn Database,
200 module_id: ModuleId<'db>,
201) -> Maybe<Diagnostics<'db, SemanticDiagnostic<'db>>> {
202 let mut diagnostics = SemanticDiagnostics::new(module_id);
203 for (_module_id, plugin_diag) in
204 module_id.module_data(db)?.plugin_diagnostics(db).iter().cloned()
205 {
206 match plugin_diag.inner_span {
207 None => diagnostics.report(
208 plugin_diag.stable_ptr,
209 SemanticDiagnosticKind::PluginDiagnostic(plugin_diag),
210 ),
211 Some(inner_span) => diagnostics.report_with_inner_span(
212 plugin_diag.stable_ptr,
213 inner_span,
214 SemanticDiagnosticKind::PluginDiagnostic(plugin_diag),
215 ),
216 };
217 }
218 let data = db.priv_module_semantic_data(module_id)?;
219 diagnostics.extend(data.diagnostics.clone());
220 for item in module_id.module_data(db)?.items(db).iter() {
223 match item {
224 ModuleItemId::Constant(const_id) => {
225 diagnostics.extend(db.constant_semantic_diagnostics(*const_id));
226 }
227 ModuleItemId::Use(use_id) => {
229 diagnostics.extend(db.use_semantic_diagnostics(*use_id));
230 }
231 ModuleItemId::FreeFunction(free_function) => {
232 diagnostics.extend(db.free_function_declaration_diagnostics(*free_function));
233 diagnostics.extend(db.free_function_body_diagnostics(*free_function));
234 }
235 ModuleItemId::Struct(struct_id) => {
236 diagnostics.extend(db.struct_declaration_diagnostics(*struct_id));
237 diagnostics.extend(db.struct_definition_diagnostics(*struct_id));
238 }
239 ModuleItemId::Enum(enum_id) => {
240 diagnostics.extend(db.enum_definition_diagnostics(*enum_id));
241 diagnostics.extend(db.enum_declaration_diagnostics(*enum_id));
242 }
243 ModuleItemId::Trait(trait_id) => {
244 diagnostics.extend(db.trait_semantic_declaration_diagnostics(*trait_id));
245 diagnostics.extend(db.trait_semantic_definition_diagnostics(*trait_id));
246 }
247 ModuleItemId::Impl(impl_def_id) => {
248 diagnostics.extend(db.impl_semantic_declaration_diagnostics(*impl_def_id));
249 diagnostics.extend(db.impl_semantic_definition_diagnostics(*impl_def_id));
250 }
251 ModuleItemId::Submodule(submodule_id) => {
252 if let Ok(file_id) = db.module_main_file(ModuleId::Submodule(*submodule_id))
254 && db.file_content(file_id).is_none()
255 {
256 let path = match file_id.long(db) {
260 FileLongId::OnDisk(path) => path.display().to_string(),
261 FileLongId::Virtual(_) | FileLongId::External(_) => {
262 panic!("Expected OnDisk file.")
263 }
264 };
265
266 diagnostics.report(
267 submodule_id.stable_ptr(db).untyped(),
268 SemanticDiagnosticKind::ModuleFileNotFound(path),
269 );
270 }
271 }
272 ModuleItemId::ExternType(extern_type) => {
273 diagnostics.extend(db.extern_type_declaration_diagnostics(*extern_type));
274 }
275 ModuleItemId::ExternFunction(extern_function) => {
276 diagnostics.extend(db.extern_function_declaration_diagnostics(*extern_function));
277 }
278 ModuleItemId::TypeAlias(type_alias) => {
279 diagnostics.extend(db.module_type_alias_semantic_diagnostics(*type_alias));
280 }
281 ModuleItemId::ImplAlias(type_alias) => {
282 diagnostics.extend(db.impl_alias_semantic_diagnostics(*type_alias));
283 }
284 ModuleItemId::MacroDeclaration(macro_declaration) => {
285 diagnostics.extend(db.macro_declaration_diagnostics(*macro_declaration));
286 }
287 }
288 }
289 for global_use in module_id.module_data(db)?.global_uses(db).keys() {
290 diagnostics.extend(db.global_use_semantic_diagnostics(*global_use));
291 }
292 for macro_call in db.module_macro_calls_ids(module_id)?.iter() {
293 diagnostics.extend(db.macro_call_diagnostics(*macro_call));
294 if let Ok(macro_module_id) = db.macro_call_module_id(*macro_call)
295 && let Ok(semantic_diags) = db.module_semantic_diagnostics(macro_module_id)
296 {
297 diagnostics.extend(semantic_diags);
298 }
299 }
300 add_unused_item_diagnostics(db, module_id, data, &mut diagnostics);
301 add_duplicated_names_from_macro_expansions_diagnostics(db, module_id, &mut diagnostics);
302 for analyzer_plugin_id in db.crate_analyzer_plugins(module_id.owning_crate(db)).iter() {
303 let analyzer_plugin = analyzer_plugin_id.long(db);
304
305 for diag in analyzer_plugin.diagnostics(db, module_id) {
306 diagnostics.report(diag.stable_ptr, SemanticDiagnosticKind::PluginDiagnostic(diag));
307 }
308 }
309
310 Ok(diagnostics.build())
311}
312
313fn add_duplicated_names_from_macro_expansions_diagnostics<'db>(
315 db: &'db dyn Database,
316 module_id: ModuleId<'db>,
317 diagnostics: &mut SemanticDiagnostics<'db>,
318) {
319 if matches!(module_id, ModuleId::MacroCall { .. }) {
320 return;
322 }
323 let mut names = UnorderedHashSet::<SmolStrId<'_>>::default();
324 for defined_module in chain!([&module_id], module_macro_modules(db, false, module_id)) {
325 let Ok(data) = db.priv_module_semantic_data(*defined_module) else {
326 continue;
327 };
328 for (name, info) in data.items.iter() {
329 if !names.insert(*name)
330 && let Ok(stable_ptr) =
331 db.module_item_name_stable_ptr(*defined_module, info.item_id)
332 {
333 diagnostics
334 .report(stable_ptr, SemanticDiagnosticKind::NameDefinedMultipleTimes(*name));
335 }
336 }
337 }
338}
339
340fn crate_analyzer_plugins<'db>(
341 db: &'db dyn Database,
342 crate_id: CrateId<'db>,
343) -> Arc<Vec<AnalyzerPluginId<'db>>> {
344 db.analyzer_plugin_overrides()
345 .get(&crate_id)
346 .cloned()
347 .unwrap_or_else(|| db.default_analyzer_plugins())
348}
349
350#[salsa::tracked]
351fn declared_allows(db: &dyn Database, crate_id: CrateId<'_>) -> Arc<OrderedHashSet<String>> {
352 let base_lints = [DEPRECATED_ATTR, UNUSED_IMPORTS, UNUSED_VARIABLES];
353
354 let crate_analyzer_plugins = db.crate_analyzer_plugins(crate_id);
355
356 Arc::new(OrderedHashSet::from_iter(chain!(
357 base_lints.map(|attr| attr.into()),
358 crate_analyzer_plugins.iter().flat_map(|plugin| plugin.long(db).declared_allows())
359 )))
360}
361
362fn add_unused_item_diagnostics<'db>(
366 db: &'db dyn Database,
367 module_id: ModuleId<'db>,
368 data: &ModuleSemanticData<'db>,
369 diagnostics: &mut SemanticDiagnostics<'db>,
370) {
371 let Ok(all_used_uses) = db.module_all_used_uses(module_id) else {
372 return;
373 };
374 for info in data.items.values() {
375 if info.visibility == Visibility::Public {
376 continue;
377 }
378 if let ModuleItemId::Use(use_id) = info.item_id {
379 add_unused_import_diagnostics(db, all_used_uses, use_id, diagnostics);
380 };
381 }
382}
383
384fn add_unused_import_diagnostics<'db>(
386 db: &'db dyn Database,
387 all_used_uses: &OrderedHashSet<UseId<'db>>,
388 use_id: UseId<'db>,
389 diagnostics: &mut SemanticDiagnostics<'db>,
390) {
391 let _iife =
392 (|| {
393 let item = db.use_resolved_item(use_id).ok()?;
394 require(!matches!(
397 item,
398 ResolvedGenericItem::Impl(_) | ResolvedGenericItem::GenericImplAlias(_)
399 ))?;
400 require(!all_used_uses.contains(&use_id))?;
401 let resolver_data = db.use_resolver_data(use_id).ok()?;
402
403 require(
404 !resolver_data
405 .feature_config
406 .allowed_lints
407 .contains(&SmolStrId::from(db, UNUSED_IMPORTS)),
408 )?;
409 Some(diagnostics.report(
410 use_id.untyped_stable_ptr(db),
411 SemanticDiagnosticKind::UnusedImport(use_id),
412 ))
413 })();
414}
415
416#[salsa::tracked]
417fn file_semantic_diagnostics<'db>(
418 db: &'db dyn Database,
419 file_id: FileId<'db>,
420) -> Maybe<Diagnostics<'db, SemanticDiagnostic<'db>>> {
421 let mut diagnostics = DiagnosticsBuilder::default();
422 for module_id in db.file_modules(file_id)?.iter().copied() {
423 if let Ok(module_diagnostics) = db.module_semantic_diagnostics(module_id) {
424 diagnostics.extend(module_diagnostics)
425 }
426 }
427 Ok(diagnostics.build())
428}
429
430#[salsa::tracked]
431pub fn lookup_resolved_generic_item_by_ptr<'db>(
432 db: &'db dyn Database,
433 id: LookupItemId<'db>,
434 ptr: ast::TerminalIdentifierPtr<'db>,
435) -> Option<ResolvedGenericItem<'db>> {
436 get_resolver_data_options(id, db)
437 .into_iter()
438 .find_map(|resolver_data| resolver_data.resolved_items.generic.get(&ptr).cloned())
439}
440
441#[salsa::tracked]
442pub fn lookup_resolved_concrete_item_by_ptr<'db>(
443 db: &'db dyn Database,
444 id: LookupItemId<'db>,
445 ptr: ast::TerminalIdentifierPtr<'db>,
446) -> Option<ResolvedConcreteItem<'db>> {
447 get_resolver_data_options(id, db)
448 .into_iter()
449 .find_map(|resolver_data| resolver_data.resolved_items.concrete.get(&ptr).cloned())
450}
451
452pub fn get_resolver_data_options<'db>(
453 id: LookupItemId<'db>,
454 db: &'db dyn Database,
455) -> Vec<Arc<ResolverData<'db>>> {
456 match id {
457 LookupItemId::ModuleItem(module_item) => match module_item {
458 ModuleItemId::Constant(id) => vec![db.constant_resolver_data(id)],
459 ModuleItemId::Submodule(_) => vec![],
460 ModuleItemId::Use(id) => vec![db.use_resolver_data(id)],
461 ModuleItemId::FreeFunction(id) => vec![
462 db.free_function_declaration_resolver_data(id),
463 db.free_function_body_resolver_data(id),
464 ],
465 ModuleItemId::Struct(id) => vec![
466 db.struct_declaration_resolver_data(id),
467 db.struct_definition_resolver_data(id),
468 ],
469 ModuleItemId::Enum(id) => {
470 vec![db.enum_definition_resolver_data(id), db.enum_declaration_resolver_data(id)]
471 }
472 ModuleItemId::TypeAlias(id) => vec![db.module_type_alias_resolver_data(id)],
473 ModuleItemId::ImplAlias(id) => vec![db.impl_alias_resolver_data(id)],
474 ModuleItemId::Trait(id) => vec![db.trait_resolver_data(id)],
475 ModuleItemId::Impl(id) => vec![db.impl_def_resolver_data(id)],
476 ModuleItemId::ExternType(_) => vec![],
477 ModuleItemId::ExternFunction(id) => {
478 vec![db.extern_function_declaration_resolver_data(id)]
479 }
480 ModuleItemId::MacroDeclaration(id) => vec![db.macro_declaration_resolver_data(id)],
481 },
482 LookupItemId::TraitItem(id) => match id {
483 cairo_lang_defs::ids::TraitItemId::Function(id) => {
484 let mut res = vec![db.trait_function_resolver_data(id)];
485 if let Ok(Some(resolver_data)) = db.trait_function_body_resolver_data(id) {
486 res.push(Ok(resolver_data));
487 }
488 res
489 }
490 cairo_lang_defs::ids::TraitItemId::Type(id) => vec![db.trait_type_resolver_data(id)],
491 cairo_lang_defs::ids::TraitItemId::Constant(id) => {
492 vec![db.trait_constant_resolver_data(id)]
493 }
494 cairo_lang_defs::ids::TraitItemId::Impl(id) => vec![db.trait_impl_resolver_data(id)],
495 },
496 LookupItemId::ImplItem(id) => match id {
497 cairo_lang_defs::ids::ImplItemId::Function(id) => {
498 vec![db.impl_function_resolver_data(id), db.impl_function_body_resolver_data(id)]
499 }
500 cairo_lang_defs::ids::ImplItemId::Type(id) => vec![db.impl_type_def_resolver_data(id)],
501 cairo_lang_defs::ids::ImplItemId::Constant(id) => {
502 vec![db.impl_constant_def_resolver_data(id)]
503 }
504 cairo_lang_defs::ids::ImplItemId::Impl(id) => vec![db.impl_impl_def_resolver_data(id)],
505 },
506 }
507 .into_iter()
508 .flatten()
509 .collect()
510}
511
512pub trait SemanticGroupEx: Database {
513 fn set_override_crate_analyzer_plugins(
517 &mut self,
518 crate_id: CrateId<'_>,
519 plugins: Arc<[AnalyzerPluginId<'_>]>,
520 ) {
521 let mut overrides = self.analyzer_plugin_overrides_input().clone();
522 let plugins = plugins.iter().map(|plugin| plugin.long(self).clone()).collect_vec();
523 overrides.insert(self.crate_input(crate_id).clone(), Arc::from(plugins));
524 let db_ref = self.as_dyn_database();
525 semantic_group_input(db_ref).set_analyzer_plugin_overrides(self).to(Some(overrides));
526 }
527}
528
529impl<T: Database + ?Sized> SemanticGroupEx for T {}
530
531pub trait PluginSuiteInput: Database {
533 fn intern_plugin_suite<'r>(&'r mut self, suite: PluginSuite) -> InternedPluginSuite<'r> {
535 let PluginSuite { plugins, inline_macro_plugins, analyzer_plugins } = suite;
536
537 let macro_plugins = plugins
538 .into_iter()
539 .map(|plugin| MacroPluginId::new(self, MacroPluginLongId(plugin)))
540 .collect::<Arc<[_]>>();
541
542 let inline_macro_plugins = Arc::new(
543 inline_macro_plugins
544 .into_iter()
545 .map(|(name, plugin)| {
546 (name, InlineMacroExprPluginId::new(self, InlineMacroExprPluginLongId(plugin)))
547 })
548 .collect::<OrderedHashMap<_, _>>(),
549 );
550
551 let analyzer_plugins = analyzer_plugins
552 .into_iter()
553 .map(|plugin| AnalyzerPluginId::new(self, AnalyzerPluginLongId(plugin)))
554 .collect::<Arc<[_]>>();
555
556 InternedPluginSuite { macro_plugins, inline_macro_plugins, analyzer_plugins }
557 }
558
559 fn set_default_plugins_from_suite(&mut self, suite: PluginSuite) {
566 let PluginSuite { plugins, inline_macro_plugins, analyzer_plugins } = suite;
567 let macro_plugins = plugins.into_iter().map(MacroPluginLongId).collect_vec();
570
571 let inline_macro_plugins = inline_macro_plugins
572 .into_iter()
573 .map(|(name, plugin)| (name, InlineMacroExprPluginLongId(plugin)))
574 .collect::<OrderedHashMap<_, _>>();
575
576 let analyzer_plugins =
577 analyzer_plugins.into_iter().map(AnalyzerPluginLongId).collect::<Vec<_>>();
578
579 defs_group_input(self.as_dyn_database())
580 .set_default_macro_plugins(self)
581 .to(Some(macro_plugins));
582 defs_group_input(self.as_dyn_database())
583 .set_default_inline_macro_plugins(self)
584 .to(Some(inline_macro_plugins));
585 semantic_group_input(self.as_dyn_database())
586 .set_default_analyzer_plugins(self)
587 .to(Some(analyzer_plugins));
588 }
589
590 fn set_override_crate_plugins_from_suite(
597 &mut self,
598 crate_id: CrateId<'_>,
599 suite: InternedPluginSuite<'_>,
600 ) {
601 let InternedPluginSuite { macro_plugins, inline_macro_plugins, analyzer_plugins } = suite;
602
603 self.set_override_crate_macro_plugins(crate_id, Arc::new(macro_plugins.to_vec()));
604 self.set_override_crate_inline_macro_plugins(crate_id, inline_macro_plugins);
605 self.set_override_crate_analyzer_plugins(crate_id, analyzer_plugins);
606 }
607}
608
609impl<T: Database + ?Sized> PluginSuiteInput for T {}
610
611pub fn module_ancestors<'db>(
614 db: &'db dyn Database,
615 mut module_id: ModuleId<'db>,
616) -> Vec<ModuleId<'db>> {
617 let mut ancestors = Vec::new();
618 ancestors.push(module_id); while let ModuleId::Submodule(submodule_id) = module_id {
620 let parent = submodule_id.parent_module(db);
621 ancestors.push(parent);
622 module_id = parent;
623 }
624 ancestors
625}
626
627pub fn module_fully_accessible_modules<'db>(
629 db: &'db dyn Database,
630 module_id: ModuleId<'db>,
631) -> OrderedHashSet<ModuleId<'db>> {
632 let mut result: Vec<ModuleId<'db>> = module_ancestors(db, module_id);
633 let mut index = 0;
634 while let Some(curr) = result.get(index).copied() {
635 index += 1;
636 if let Ok(macro_call_ids) = db.module_macro_calls_ids(curr) {
637 for macro_call_id in macro_call_ids.iter() {
638 if let Ok(generated_module_id) = db.macro_call_module_id(*macro_call_id) {
639 result.push(generated_module_id);
640 }
641 }
642 }
643 }
644 result.into_iter().collect()
645}
646
647#[derive(PartialEq, Eq, Clone, salsa::Update)]
649pub struct ModuleSemanticDataCacheAndLoadingData<'db> {
650 pub modules_semantic_data: Arc<OrderedHashMap<ModuleId<'db>, ModuleSemanticData<'db>>>,
652 pub impl_aliases_resolved_impls: Arc<OrderedHashMap<ImplAliasId<'db>, ImplId<'db>>>,
654 pub loading_data: Arc<SemanticCacheLoadingData<'db>>,
656}
657
658#[salsa::tracked]
659fn cached_crate_semantic_data<'db>(
660 db: &'db dyn Database,
661 crate_id: CrateId<'db>,
662) -> Option<ModuleSemanticDataCacheAndLoadingData<'db>> {
663 load_cached_crate_modules_semantic(db, crate_id)
664}