use std::collections::HashMap;
use syntax::ast::*;
use syntax::attr;
use syntax::source_map::Span;
use syntax_pos::sym;
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> {
#[cfg_attr(feature = "profile", flame)]
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,
}
}
#[cfg_attr(feature = "profile", flame)]
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, sym::no_core) {
(&[], false)
} else if attr::contains_name(&krate.attrs, sym::no_std) {
if attr::contains_name(&krate.attrs, sym::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.to_vec();
krate.module.items.retain(|i| {
match i.kind {
ItemKind::ExternCrate(_) => {
if let Some(index) = crate_names.iter().position(|s| i.ident.as_str() == *s) {
crate_names.remove(index);
false
} else {
true
}
}
ItemKind::Use(_) => {
if expect_prelude && attr::contains_name(&i.attrs, sym::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)
}
}