use c2rust_ast_builder::IntoSymbol;
use std::collections::{HashMap, HashSet};
use syntax::ast::*;
use syntax::attr;
use syntax::source_map::Span;
mod cfg_attr;
mod deleted;
mod mac_table;
mod macros;
mod node_map;
mod nt_match;
pub use self::cfg_attr::{collect_cfg_attrs, restore_cfg_attrs};
pub use self::deleted::{collect_deleted_nodes, restore_deleted_nodes};
pub use self::mac_table::{collect_macro_invocations, MacInfo, MacTable};
pub use self::macros::collapse_macros;
pub use self::node_map::match_nonterminal_ids;
use crate::command::CommandState;
use crate::node_map::NodeMap;
use deleted::DeletedNode;
pub struct CollapseInfo<'ast> {
mac_table: MacTable<'ast>,
cfg_attr_info: HashMap<NodeId, Vec<Attribute>>,
deleted_info: Vec<DeletedNode<'ast>>,
}
impl<'ast> CollapseInfo<'ast> {
pub fn collect(
unexpanded: &'ast Crate,
expanded: &'ast Crate,
node_map: &mut NodeMap,
cs: &CommandState,
) -> Self {
let (mac_table, matched_ids) = collect_macro_invocations(unexpanded, expanded);
node_map.add_edges(&matched_ids);
node_map.add_edges(&[(CRATE_NODE_ID, CRATE_NODE_ID)]);
let cfg_attr_info = collect_cfg_attrs(&unexpanded);
let deleted_info = collect_deleted_nodes(&unexpanded, &node_map, &mac_table);
match_nonterminal_ids(node_map, &mac_table);
node_map.transfer_marks(&mut cs.marks_mut());
let cfg_attr_info = node_map.transfer_map(cfg_attr_info);
node_map.commit();
CollapseInfo {
mac_table,
cfg_attr_info,
deleted_info,
}
}
pub fn collapse(self, node_map: &mut NodeMap, cs: &CommandState) {
collapse_injected(&mut cs.krate_mut());
let matched_ids = collapse_macros(&mut cs.krate_mut(), &self.mac_table);
node_map.add_edges(&matched_ids);
node_map.add_edges(&[(CRATE_NODE_ID, CRATE_NODE_ID)]);
let cfg_attr_info = node_map.transfer_map(self.cfg_attr_info);
restore_cfg_attrs(&mut cs.krate_mut(), cfg_attr_info);
restore_deleted_nodes(
&mut cs.krate_mut(),
node_map,
cs.node_id_counter(),
self.deleted_info,
);
node_map.transfer_marks(&mut cs.marks_mut());
node_map.commit();
}
}
fn injected_items(krate: &Crate) -> (&'static [&'static str], bool) {
if attr::contains_name(&krate.attrs, "no_core") {
(&[], false)
} else if attr::contains_name(&krate.attrs, "no_std") {
if attr::contains_name(&krate.attrs, "compiler_builtins") {
(&["core"], true)
} else {
(&["core", "compiler_builtins"], true)
}
} else {
(&["std"], true)
}
}
pub fn collapse_injected(krate: &mut Crate) {
let (crate_names, mut expect_prelude) = injected_items(krate);
let mut crate_names = crate_names
.iter()
.map(|x| x.into_symbol())
.collect::<HashSet<_>>();
krate.module.items.retain(|i| {
match i.node {
ItemKind::ExternCrate(_) => {
if crate_names.remove(&i.ident.name) {
false
} else {
true
}
}
ItemKind::Use(_) => {
if expect_prelude && attr::contains_name(&i.attrs, "prelude_import") {
expect_prelude = false;
false
} else {
true
}
}
_ => true,
}
});
}
fn root_callsite_span(sp: Span) -> Span {
let callsite = sp.source_callsite();
if callsite == sp {
sp
} else {
root_callsite_span(callsite)
}
}