use smallvec::SmallVec;
use std::collections::{HashMap, HashSet};
use std::mem;
use syntax::ast::*;
use syntax::mut_visit::{self, MutVisitor};
use syntax::ptr::P;
use syntax::visit::{self, Visitor};
use crate::ast_manip::number_nodes::{number_nodes_with, NodeIdCounter};
use crate::ast_manip::{GetNodeId, ListNodeIds, MutVisit, Visit};
use crate::node_map::NodeMap;
use super::mac_table::{AsMacNodeRef, MacNodeRef, MacTable};
#[derive(Clone, Debug)]
pub struct DeletedNode<'ast> {
id: NodeId,
parent: NodeId,
preds: Vec<NodeId>,
node: MacNodeRef<'ast>,
saved_origins: Vec<Option<NodeId>>,
}
struct CollectDeletedNodes<'a, 'ast> {
table: &'a MacTable<'ast>,
node_map: &'a NodeMap,
deleted: Vec<DeletedNode<'ast>>,
}
impl<'a, 'ast> CollectDeletedNodes<'a, 'ast> {
fn handle_seq<T>(&mut self, parent: NodeId, nodes: &'ast [T])
where
T: GetNodeId + ListNodeIds + AsMacNodeRef,
{
let mut history = Vec::with_capacity(nodes.len());
for n in nodes {
let id = n.get_node_id();
if self.table.empty_invocs.contains_key(&id) {
let origins = n
.list_node_ids()
.into_iter()
.map(|id| self.node_map.save_origin(id))
.collect();
self.deleted.push(DeletedNode {
id,
parent,
preds: history.clone(),
node: n.as_mac_node_ref(),
saved_origins: origins,
});
} else {
history.push(id);
}
}
}
fn handle_crate(&mut self, x: &'ast Crate) {
self.handle_seq(CRATE_NODE_ID, &x.module.items);
}
}
impl<'a, 'ast> Visitor<'ast> for CollectDeletedNodes<'a, 'ast> {
fn visit_item(&mut self, x: &'ast Item) {
match x.node {
ItemKind::Mod(ref m) => self.handle_seq(x.id, &m.items),
ItemKind::ForeignMod(ref fm) => self.handle_seq(x.id, &fm.items),
ItemKind::Trait(_, _, _, _, ref items) => self.handle_seq(x.id, items),
ItemKind::Impl(_, _, _, _, _, _, ref items) => self.handle_seq(x.id, items),
_ => {}
}
visit::walk_item(self, x);
}
fn visit_mac(&mut self, mac: &'ast Mac) {
visit::walk_mac(self, mac)
}
}
fn transfer_deleted_nodes<'ast>(
node_map: &NodeMap,
dns: Vec<DeletedNode<'ast>>,
) -> Vec<DeletedNode<'ast>> {
let mut result = Vec::with_capacity(dns.len());
for mut dn in dns {
dn.preds = dn
.preds
.iter()
.flat_map(|&id| node_map.transfer(id))
.collect::<Vec<_>>();
let mut iter = node_map.transfer(dn.parent).peekable();
let mut opt_dn = Some(dn);
while let Some(new_parent) = iter.next() {
let base_dn = if iter.peek().is_none() {
opt_dn.take().unwrap()
} else {
opt_dn.as_ref().unwrap().clone()
};
result.push(DeletedNode {
parent: new_parent,
..base_dn
});
}
}
result
}
pub fn collect_deleted_nodes<'ast>(
krate: &'ast Crate,
node_map: &NodeMap,
table: &MacTable<'ast>,
) -> Vec<DeletedNode<'ast>> {
let mut v = CollectDeletedNodes {
table,
node_map,
deleted: Vec::new(),
};
v.handle_crate(krate);
krate.visit(&mut v);
transfer_deleted_nodes(node_map, v.deleted)
}
struct RestoreDeletedNodes<'a, 'ast> {
node_map: &'a mut NodeMap,
counter: &'a NodeIdCounter,
deleted: HashMap<NodeId, Vec<DeletedNode<'ast>>>,
}
impl<'a, 'ast> RestoreDeletedNodes<'a, 'ast> {
fn restore_seq<T>(&mut self, parent: NodeId, nodes: &mut Vec<T>)
where
T: GetNodeId + ListNodeIds + MutVisit + AsMacNodeRef,
{
let deleted = match_or!([self.deleted.get(&parent)]
Some(x) => x; return);
let present = nodes
.iter()
.map(|x| x.get_node_id())
.collect::<HashSet<_>>();
let mut ins_after: HashMap<NodeId, Vec<&DeletedNode>> = HashMap::new();
for dn in deleted {
let last_pred = dn
.preds
.iter()
.cloned()
.filter(|&id| present.contains(&id))
.last()
.unwrap_or(DUMMY_NODE_ID);
ins_after.entry(last_pred).or_insert_with(Vec::new).push(dn);
}
let result = Vec::with_capacity(nodes.len() + deleted.len());
let old_nodes = mem::replace(nodes, result);
let counter = self.counter;
let node_map = &mut *self.node_map;
let mut push_ins_after = |nodes: &mut Vec<_>, id| {
for dn in ins_after.remove(&id).into_iter().flat_map(|x| x) {
let mut n = T::clone_from_mac_node_ref(dn.node);
number_nodes_with(&mut n, counter);
for (id, &origin) in n.list_node_ids().into_iter().zip(&dn.saved_origins) {
node_map.restore_origin(id, origin);
node_map.add_edge(id, id);
}
nodes.push(n);
}
};
push_ins_after(nodes, DUMMY_NODE_ID);
for n in old_nodes {
let id = n.get_node_id();
nodes.push(n);
push_ins_after(nodes, id);
}
}
}
impl<'a, 'ast> MutVisitor for RestoreDeletedNodes<'a, 'ast> {
fn visit_crate(&mut self, x: &mut Crate) {
self.restore_seq(CRATE_NODE_ID, &mut x.module.items);
mut_visit::noop_visit_crate(x, self)
}
fn flat_map_item(&mut self, x: P<Item>) -> SmallVec<[P<Item>; 1]> {
let x = x.map(|mut x| {
match x.node {
ItemKind::Mod(ref mut m) => self.restore_seq(x.id, &mut m.items),
ItemKind::ForeignMod(ref mut fm) => self.restore_seq(x.id, &mut fm.items),
ItemKind::Trait(_, _, _, _, ref mut items) => self.restore_seq(x.id, items),
ItemKind::Impl(_, _, _, _, _, _, ref mut items) => self.restore_seq(x.id, items),
_ => {}
}
x
});
mut_visit::noop_flat_map_item(x, self)
}
fn visit_mac(&mut self, mac: &mut Mac) {
mut_visit::noop_visit_mac(mac, self)
}
}
fn index_deleted_nodes<'ast>(
vec: Vec<DeletedNode<'ast>>,
) -> HashMap<NodeId, Vec<DeletedNode<'ast>>> {
let mut map = HashMap::new();
for dn in vec {
map.entry(dn.parent).or_insert_with(Vec::new).push(dn);
}
map
}
pub fn restore_deleted_nodes(
krate: &mut Crate,
node_map: &mut NodeMap,
counter: &NodeIdCounter,
deleted: Vec<DeletedNode>,
) {
let deleted = transfer_deleted_nodes(node_map, deleted);
let deleted = index_deleted_nodes(deleted);
let mut f = RestoreDeletedNodes {
node_map,
counter,
deleted,
};
krate.visit(&mut f)
}