use rustc::hir::{self, intravisit};
use rustc::ty::{self, TyCtxt};
use syntax::symbol::Symbol;
#[derive(Copy, Clone)]
pub(crate) struct RerastDefinitions<'gcx> {
pub(crate) statements: ty::Ty<'gcx>,
pub(crate) expr_rule_marker: ty::Ty<'gcx>,
pub(crate) pattern_rule_marker: ty::Ty<'gcx>,
pub(crate) type_rule_marker: ty::Ty<'gcx>,
pub(crate) trait_ref_rule_marker: ty::Ty<'gcx>,
pub(crate) search_symbol: Symbol,
pub(crate) replace_symbol: Symbol,
}
pub(crate) struct RerastDefinitionsFinder<'a, 'gcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'gcx>,
rerast_mod_symbol: Symbol,
rerast_types_symbol: Symbol,
inside_rerast_mod: bool,
definitions: Option<RerastDefinitions<'gcx>>,
}
impl<'a, 'gcx> RerastDefinitionsFinder<'a, 'gcx> {
pub(crate) fn find_definitions(
tcx: TyCtxt<'a, 'gcx, 'gcx>,
krate: &'gcx hir::Crate,
) -> Option<RerastDefinitions<'gcx>> {
let mut finder = RerastDefinitionsFinder {
tcx,
rerast_mod_symbol: Symbol::intern(super::RERAST_INTERNAL_MOD_NAME),
rerast_types_symbol: Symbol::intern("rerast_types"),
inside_rerast_mod: false,
definitions: None,
};
intravisit::walk_crate(&mut finder, krate);
finder.definitions
}
}
impl<'a, 'gcx, 'tcx> intravisit::Visitor<'gcx> for RerastDefinitionsFinder<'a, 'gcx> {
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'gcx> {
intravisit::NestedVisitorMap::All(&self.tcx.hir())
}
fn visit_item(&mut self, item: &'gcx hir::Item) {
if self.inside_rerast_mod {
intravisit::walk_item(self, item);
} else if let hir::ItemKind::Mod(_) = item.node {
if item.ident.name == self.rerast_mod_symbol {
self.inside_rerast_mod = true;
intravisit::walk_item(self, item);
self.inside_rerast_mod = false;
}
}
}
fn visit_body(&mut self, body: &'gcx hir::Body) {
let fn_id = self.tcx.hir().body_owner_def_id(body.id());
if self.tcx.item_name(fn_id) == self.rerast_types_symbol {
let tables = self.tcx.typeck_tables_of(fn_id);
let mut types = body
.arguments
.iter()
.map(|arg| tables.node_type(arg.hir_id));
self.definitions = Some(RerastDefinitions {
statements: types
.next()
.expect("Internal error - missing type: statements"),
expr_rule_marker: types
.next()
.expect("Internal error - missing type: expr_rule_marker"),
pattern_rule_marker: types
.next()
.expect("Internal error - missing type: pattern_rule_marker"),
type_rule_marker: types
.next()
.expect("Internal error - missing type: type_rule_marker"),
trait_ref_rule_marker: types
.next()
.expect("Internal error - missing type: trait_ref_rule_marker"),
search_symbol: Symbol::intern("Search"),
replace_symbol: Symbol::intern("Replace"),
})
}
}
}