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