use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
use ecow::EcoString;
use crate::ast::{BindingId as AstBindingId, Pattern, RestPattern, Span};
use crate::types::Symbol;
use super::{Definition, File, ModuleInfo};
#[derive(Debug, Clone, Default)]
pub struct UnusedInfo {
bindings: HashSet<Span>,
definitions: HashSet<Span>,
pub imports_by_module: HashMap<EcoString, HashSet<EcoString>>,
}
impl UnusedInfo {
pub fn mark_binding_unused(&mut self, span: Span) {
self.bindings.insert(span);
}
pub fn is_unused_binding(&self, pattern: &Pattern) -> bool {
match pattern {
Pattern::Identifier { span, .. } => self.bindings.contains(span),
Pattern::AsBinding { span, name, .. } => {
let name_span = Span::new(
span.file_id,
span.byte_offset + span.byte_length - name.len() as u32,
name.len() as u32,
);
self.bindings.contains(&name_span)
}
_ => false,
}
}
pub fn is_unused_rest_binding(&self, rest: &RestPattern) -> bool {
match rest {
RestPattern::Bind { span, .. } => self.bindings.contains(span),
_ => false,
}
}
pub fn mark_definition_unused(&mut self, span: Span) {
self.definitions.insert(span);
}
pub fn is_unused_definition(&self, span: &Span) -> bool {
self.definitions.contains(span)
}
pub fn merge(&mut self, other: UnusedInfo) {
let UnusedInfo {
bindings,
definitions,
imports_by_module,
} = other;
self.bindings.extend(bindings);
self.definitions.extend(definitions);
for (module, imports) in imports_by_module {
self.imports_by_module
.entry(module)
.or_default()
.extend(imports);
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MutationInfo {
bindings: HashSet<AstBindingId>,
}
impl MutationInfo {
pub fn mark_binding_mutated(&mut self, id: AstBindingId) {
self.bindings.insert(id);
}
pub fn is_mutated(&self, id: AstBindingId) -> bool {
self.bindings.contains(&id)
}
}
pub struct EmitInput {
pub files: HashMap<u32, File>,
pub definitions: HashMap<Symbol, Definition>,
pub modules: HashMap<String, ModuleInfo>,
pub entry_module_id: String,
pub unused: UnusedInfo,
pub mutations: MutationInfo,
pub cached_modules: HashSet<String>,
pub ufcs_methods: HashSet<(String, String)>,
pub go_package_names: HashMap<String, String>,
pub go_module_ids: HashSet<String>,
}
#[cfg(test)]
mod tests {
use super::*;
fn span(offset: u32) -> Span {
Span::new(0, offset, 1)
}
#[test]
fn merge_extends_bindings_definitions_and_imports() {
let mut a = UnusedInfo::default();
a.mark_binding_unused(span(0));
a.mark_definition_unused(span(1));
a.imports_by_module
.insert("m1".into(), HashSet::from_iter(["x".into()]));
let mut b = UnusedInfo::default();
b.mark_binding_unused(span(2));
b.mark_definition_unused(span(3));
b.imports_by_module
.insert("m1".into(), HashSet::from_iter(["y".into()]));
b.imports_by_module
.insert("m2".into(), HashSet::from_iter(["z".into()]));
a.merge(b);
assert_eq!(a.bindings.len(), 2);
assert_eq!(a.definitions.len(), 2);
assert_eq!(a.imports_by_module["m1"].len(), 2);
assert_eq!(a.imports_by_module["m2"].len(), 1);
}
}