use crate::code::ASTMetadata;
use crate::diff::{ASTDiff, ASTMappingOperation, PassCtx};
fn lost_named_sibling(
meta: &ASTMetadata,
parent: usize,
leaf: usize,
node_map: &rustc_hash::FxHashMap<usize, usize>,
) -> bool {
meta.node_info.get(&parent).is_some_and(|info| {
info.children.iter().any(|&child| {
child != leaf
&& node_map.get(&child).is_none_or(|&partner| partner == 0)
&& meta.node_info.get(&child).is_some_and(|c| c.is_named)
})
})
}
fn kind(meta: &ASTMetadata, id: usize) -> Option<&str> {
meta.node_info.get(&id).map(|info| info.kind.as_str())
}
pub fn solve(ctx: &PassCtx, diff: &mut ASTDiff) {
let (before, after) = (ctx.before_metadata(), ctx.after_metadata());
let is_leaf = |meta: &ASTMetadata, id: usize| {
meta.node_info
.get(&id)
.is_some_and(|info| info.children.is_empty())
};
let mut stray: Vec<(usize, usize)> = diff
.mapping
.iter()
.filter(|&(&(b, a), mapping)| {
b != 0 && a != 0 && mapping.operation == ASTMappingOperation::Update
})
.map(|(&pair, _)| pair)
.filter(|&(b, a)| {
if !is_leaf(before, b) || !is_leaf(after, a) {
return false;
}
let (Some(&before_parent), Some(&after_parent)) =
(before.node_to_parent.get(&b), after.node_to_parent.get(&a))
else {
return false;
};
diff.before_node_map.get(&before_parent) != Some(&after_parent)
&& kind(before, before_parent) != kind(after, after_parent)
&& lost_named_sibling(before, before_parent, b, &diff.before_node_map)
})
.collect();
stray.sort_unstable();
for (b, a) in stray {
diff.remove_match_mapping(b, a);
}
}