use rustc::hir;
use rustc::hir::def::Def;
use smallvec::SmallVec;
use syntax::ast::*;
use syntax::mut_visit::{self, MutVisitor};
use syntax::ptr::P;
use syntax::util::map_in_place::MapInPlace;
use crate::ast_manip::util::split_uses;
use crate::ast_manip::MutVisit;
use crate::RefactorCtxt;
struct ResolvedPathFolder<'a, 'tcx: 'a, F>
where
F: FnMut(NodeId, Option<QSelf>, Path, &Def) -> (Option<QSelf>, Path),
{
cx: &'a RefactorCtxt<'a, 'tcx>,
callback: F,
}
impl<'a, 'tcx, F> ResolvedPathFolder<'a, 'tcx, F>
where
F: FnMut(NodeId, Option<QSelf>, Path, &Def) -> (Option<QSelf>, Path),
{
pub fn alter_pat_path(&mut self, p: &mut P<Pat>, hir: &hir::Pat) {
let id = p.id;
match hir.node {
hir::PatKind::Struct(ref qpath, _, _) => {
unpack!([&mut p.node] PatKind::Struct(path, _fields, _dotdot));
let (new_qself, new_path) = self.handle_qpath(id, None, path.clone(), qpath);
assert!(
new_qself.is_none(),
"can't insert QSelf at this location (PatKind::Struct)"
);
*path = new_path;
}
hir::PatKind::TupleStruct(ref qpath, _, _) => {
unpack!([&mut p.node] PatKind::TupleStruct(path, _fields, _dotdot_pos));
let (new_qself, new_path) = self.handle_qpath(id, None, path.clone(), qpath);
assert!(
new_qself.is_none(),
"can't insert QSelf at this location (PatKind::TupleStruct)"
);
*path = new_path;
}
hir::PatKind::Path(ref qpath) => {
let (qself, path) = match &mut p.node {
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) => {
(None, Path::from_ident(*ident))
}
PatKind::Path(qself, path) => (qself.clone(), path.clone()),
_ => panic!("expected PatKind::Ident or PatKind::Path"),
};
let (new_qself, new_path) = self.handle_qpath(id, qself, path, qpath);
if new_qself.is_none() && new_path.segments.len() == 1 {
p.node = PatKind::Ident(
BindingMode::ByValue(Mutability::Immutable),
new_path.segments[0].ident,
None,
);
} else {
p.node = PatKind::Path(new_qself, new_path);
};
}
_ => {}
}
}
pub fn alter_expr_path(&mut self, e: &mut P<Expr>, hir: &hir::Expr) {
let id = e.id;
match hir.node {
hir::ExprKind::Path(ref qpath) => {
unpack!([&mut e.node] ExprKind::Path(qself, path));
let (new_qself, new_path) =
self.handle_qpath(id, qself.clone(), path.clone(), qpath);
e.node = ExprKind::Path(new_qself, new_path);
}
hir::ExprKind::Struct(ref qpath, _, _) => {
match e.node {
ExprKind::Range(_, _, _) => return,
_ => {}
}
unpack!([&mut e.node] ExprKind::Struct(path, _fields, _base));
let (new_qself, new_path) = self.handle_qpath(id, None, path.clone(), qpath);
assert!(
new_qself.is_none(),
"can't insert QSelf at this location (ExprKind::Struct)"
);
*path = new_path;
}
_ => {}
}
}
pub fn alter_ty_path(&mut self, t: &mut P<Ty>, hir: &hir::Ty) {
let id = t.id;
match hir.node {
hir::TyKind::Path(ref qpath) => {
match t.node {
TyKind::ImplicitSelf => return,
_ => {}
}
unpack!([&mut t.node] TyKind::Path(qself, path));
let (new_qself, new_path) =
self.handle_qpath(id, qself.clone(), path.clone(), qpath);
*qself = new_qself;
*path = new_path;
}
_ => {}
}
}
pub fn alter_use_path(&mut self, item: &mut P<Item>, hir: &hir::Item) {
let id = item.id;
unpack!([&mut item.node] ItemKind::Use(tree));
if let hir::ItemKind::Use(ref hir_path, _) = hir.node {
debug!("{:?}", hir_path);
let (_, new_path) = (self.callback)(id, None, tree.prefix.clone(), &hir_path.def);
tree.prefix = new_path;
}
}
fn handle_qpath(
&mut self,
id: NodeId,
qself: Option<QSelf>,
path: Path,
hir_qpath: &hir::QPath,
) -> (Option<QSelf>, Path) {
match *hir_qpath {
hir::QPath::Resolved(_, ref hir_path) => {
(self.callback)(id, qself, path, &hir_path.def)
}
hir::QPath::TypeRelative(ref hir_ty, _) => {
let mut path = path;
let tail = path.segments.pop().unwrap();
let (new_qself, mut new_path) = self.handle_relative_path(id, qself, path, hir_ty);
new_path.segments.push(tail);
(new_qself, new_path)
}
}
}
fn handle_relative_path(
&mut self,
id: NodeId,
qself: Option<QSelf>,
path: Path,
hir_ty: &hir::Ty,
) -> (Option<QSelf>, Path) {
match hir_ty.node {
hir::TyKind::Path(ref qpath) => self.handle_qpath(id, qself, path, qpath),
_ => (qself, path),
}
}
}
impl<'a, 'tcx, F> MutVisitor for ResolvedPathFolder<'a, 'tcx, F>
where
F: FnMut(NodeId, Option<QSelf>, Path, &Def) -> (Option<QSelf>, Path),
{
fn visit_pat(&mut self, p: &mut P<Pat>) {
if let Some(node) = self.cx.hir_map().find(p.id) {
let hir = expect!([node]
hir::Node::Pat(pat) => pat,
hir::Node::Binding(pat) => pat);
self.alter_pat_path(p, hir);
}
mut_visit::noop_visit_pat(p, self)
}
fn visit_expr(&mut self, e: &mut P<Expr>) {
if let Some(node) = self.cx.hir_map().find(e.id) {
let hir = expect!([node]
hir::Node::Expr(expr) => expr);
self.alter_expr_path(e, hir);
}
mut_visit::noop_visit_expr(e, self)
}
fn visit_ty(&mut self, t: &mut P<Ty>) {
if let Some(node) = self.cx.hir_map().find(t.id) {
let hir = expect!([node]
hir::Node::Ty(ty) => ty);
self.alter_ty_path(t, hir);
}
mut_visit::noop_visit_ty(t, self)
}
fn flat_map_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 1]> {
let mut v = match item.node {
ItemKind::Use(..) => {
let mut uses = split_uses(item);
for item in uses.iter_mut() {
if let Some(node) = self.cx.hir_map().find(item.id) {
let hir = expect!([node] hir::Node::Item(i) => i);
self.alter_use_path(item, hir)
}
}
uses
}
_ => smallvec![item],
};
v.flat_map_in_place(|item| mut_visit::noop_flat_map_item(item, self));
v
}
}
pub fn fold_resolved_paths<T, F>(target: &mut T, cx: &RefactorCtxt, mut callback: F)
where
T: MutVisit,
F: FnMut(Option<QSelf>, Path, &Def) -> (Option<QSelf>, Path),
{
let mut f = ResolvedPathFolder {
cx: cx,
callback: |_, q, p, d| callback(q, p, d),
};
target.visit(&mut f)
}
pub fn fold_resolved_paths_with_id<T, F>(target: &mut T, cx: &RefactorCtxt, callback: F)
where
T: MutVisit,
F: FnMut(NodeId, Option<QSelf>, Path, &Def) -> (Option<QSelf>, Path),
{
let mut f = ResolvedPathFolder {
cx: cx,
callback: callback,
};
target.visit(&mut f)
}