use diagnostics::LocalSink;
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
use syntax::program::{Definition, DefinitionBody, Visibility};
use crate::store::Store;
pub(crate) fn run_module(module_id: &str, store: &Store, sink: &LocalSink) {
let Some(module) = store.get_module(module_id) else {
return;
};
let module_prefix = format!("{}.", module_id);
let non_pub_interfaces: HashMap<String, HashSet<String>> = module
.definitions
.iter()
.filter(|(key, _)| key.starts_with(&module_prefix))
.filter_map(|(_, definition)| {
if let Definition {
visibility: Visibility::Private,
body:
DefinitionBody::Interface {
definition: interface_data,
},
..
} = definition
{
let method_names = interface_data
.methods
.keys()
.map(|k| k.to_string())
.collect();
Some((interface_data.name.to_string(), method_names))
} else {
None
}
})
.collect();
if non_pub_interfaces.is_empty() {
return;
}
for (_, definition) in module
.definitions
.iter()
.filter(|(key, _)| key.starts_with(&module_prefix))
{
if let Definition {
name: Some(name),
name_span: Some(name_span),
body: DefinitionBody::Struct { methods, .. },
..
} = definition
{
for method_name in methods.keys() {
for (interface_name, interface_methods) in &non_pub_interfaces {
if interface_methods.contains(method_name.as_str()) {
let method_key = format!("{}.{}.{}", module_id, name, method_name);
let method_is_pub = module
.definitions
.get(method_key.as_str())
.map(|definition| definition.visibility().is_public())
.unwrap_or(false);
if method_is_pub {
sink.push(diagnostics::infer::non_pub_interface_with_pub_impl(
interface_name,
name,
*name_span,
));
return;
}
}
}
}
}
}
}