rust-clippy/clippy_lints/src/utils/hir.rs

554 lines
21 KiB
Rust
Raw Normal View History

2016-02-06 19:13:25 +00:00
use consts::constant;
use rustc::lint::*;
use rustc::hir::*;
2016-02-09 14:18:27 +00:00
use std::hash::{Hash, Hasher, SipHasher};
use syntax::ast::Name;
2016-02-06 19:13:25 +00:00
use syntax::ptr::P;
use utils::differing_macro_contexts;
2016-02-06 19:13:25 +00:00
/// Type used to check whether two ast are the same. This is different from the operator
/// `==` on ast types as this operator would compare true equality with ID and span.
///
/// Note that some expressions kinds are not considered but could be added.
pub struct SpanlessEq<'a, 'tcx: 'a> {
/// Context used to evaluate constant expressions.
cx: &'a LateContext<'a, 'tcx>,
/// If is true, never consider as equal expressions containing function calls.
2016-02-06 19:13:25 +00:00
ignore_fn: bool,
}
impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
2016-02-24 16:38:57 +00:00
SpanlessEq {
cx: cx,
ignore_fn: false,
}
2016-02-06 19:13:25 +00:00
}
pub fn ignore_fn(self) -> Self {
2016-02-24 16:38:57 +00:00
SpanlessEq {
cx: self.cx,
ignore_fn: true,
}
2016-02-06 19:13:25 +00:00
}
/// Check whether two statements are the same.
pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool {
match (&left.node, &right.node) {
(&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => {
if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) {
both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) &&
both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
2016-02-29 11:19:32 +00:00
} else {
2016-02-06 19:13:25 +00:00
false
}
}
(&StmtExpr(ref l, _), &StmtExpr(ref r, _)) |
2016-02-24 16:38:57 +00:00
(&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r),
2016-02-06 19:13:25 +00:00
_ => false,
}
}
/// Check whether two blocks are the same.
pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
2016-02-24 16:38:57 +00:00
both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
2016-02-06 19:13:25 +00:00
}
pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
if self.ignore_fn && differing_macro_contexts(left.span, right.span) {
return false;
}
2016-02-06 19:13:25 +00:00
if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) {
if l == r {
return true;
}
}
match (&left.node, &right.node) {
(&ExprAddrOf(l_mut, ref le), &ExprAddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re),
(&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()),
2016-02-29 11:19:32 +00:00
(&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr),
2016-02-06 19:13:25 +00:00
(&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
}
2016-02-24 16:38:57 +00:00
(&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
(&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) ||
2016-04-14 18:14:03 +00:00
swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
})
2016-02-06 19:13:25 +00:00
}
(&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()),
2016-02-29 11:19:32 +00:00
(&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
(&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
!self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
2016-02-06 19:13:25 +00:00
}
(&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) |
(&ExprType(ref lx, ref lt), &ExprType(ref rx, ref rt)) => {
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
}
(&ExprField(ref l_f_exp, ref l_f_ident), &ExprField(ref r_f_exp, ref r_f_ident)) => {
l_f_ident.node == r_f_ident.node && self.eq_expr(l_f_exp, r_f_exp)
2016-02-06 19:13:25 +00:00
}
2016-02-29 11:19:32 +00:00
(&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
2016-02-06 19:13:25 +00:00
(&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => {
2016-02-29 11:19:32 +00:00
self.eq_expr(lc, rc) && self.eq_block(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
2016-02-06 19:13:25 +00:00
}
(&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
2016-02-06 21:41:12 +00:00
(&ExprLoop(ref lb, ref ll), &ExprLoop(ref rb, ref rl)) => {
self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str())
2016-02-06 21:41:12 +00:00
}
2016-02-06 19:13:25 +00:00
(&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
2016-02-29 11:19:32 +00:00
ls == rs && self.eq_expr(le, re) &&
over(la, ra, |l, r| {
self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
})
}
(&ExprMethodCall(ref l_name, ref l_tys, ref l_args),
&ExprMethodCall(ref r_name, ref r_tys, ref r_args)) => {
!self.ignore_fn && l_name.node == r_name.node &&
over(l_tys, r_tys, |l, r| self.eq_ty(l, r)) &&
self.eq_exprs(l_args, r_args)
2016-02-06 19:13:25 +00:00
}
2016-02-29 11:19:32 +00:00
(&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => self.eq_expr(le, re) && self.eq_expr(ll, rl),
(&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprPath(ref l_qself, ref l_subpath), &ExprPath(ref r_qself, ref r_subpath)) => {
both(l_qself, r_qself, |l, r| self.eq_qself(l, r)) && self.eq_path(l_subpath, r_subpath)
2016-02-06 19:13:25 +00:00
}
(&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
2016-04-14 18:14:03 +00:00
self.eq_path(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
over(lf, rf, |l, r| self.eq_field(l, r))
2016-03-07 15:30:02 +00:00
}
(&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
2016-02-29 11:19:32 +00:00
(&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
(&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
2016-02-06 19:13:25 +00:00
(&ExprVec(ref l), &ExprVec(ref r)) => self.eq_exprs(l, r),
(&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => {
self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str())
2016-02-06 19:13:25 +00:00
}
_ => false,
}
}
fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool {
over(left, right, |l, r| self.eq_expr(l, r))
}
2016-03-07 15:30:02 +00:00
fn eq_field(&self, left: &Field, right: &Field) -> bool {
left.name.node == right.name.node && self.eq_expr(&left.expr, &right.expr)
}
fn eq_lifetime(&self, left: &Lifetime, right: &Lifetime) -> bool {
left.name == right.name
}
2016-02-06 19:13:25 +00:00
/// Check whether two patterns are the same.
pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool {
match (&left.node, &right.node) {
2016-02-29 11:19:32 +00:00
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
self.eq_path(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
2016-02-06 19:13:25 +00:00
}
2016-05-31 17:17:31 +00:00
(&PatKind::Binding(ref lb, ref li, ref lp), &PatKind::Binding(ref rb, ref ri, ref rp)) => {
lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
2016-02-06 19:13:25 +00:00
}
(&PatKind::Path(ref ql, ref l), &PatKind::Path(ref qr, ref r)) => {
both(ql, qr, |ql, qr| self.eq_qself(ql, qr)) && self.eq_path(l, r)
2016-02-06 19:13:25 +00:00
}
(&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
(&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
}
(&PatKind::Range(ref ls, ref le), &PatKind::Range(ref rs, ref re)) => {
2016-02-29 11:19:32 +00:00
self.eq_expr(ls, rs) && self.eq_expr(le, re)
2016-02-06 19:13:25 +00:00
}
2016-02-29 11:19:32 +00:00
(&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
(&PatKind::Vec(ref ls, ref li, ref le), &PatKind::Vec(ref rs, ref ri, ref re)) => {
2016-02-29 11:19:32 +00:00
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) &&
both(li, ri, |l, r| self.eq_pat(l, r))
2016-02-06 19:13:25 +00:00
}
(&PatKind::Wild, &PatKind::Wild) => true,
2016-02-06 19:13:25 +00:00
_ => false,
}
}
fn eq_path(&self, left: &Path, right: &Path) -> bool {
left.global == right.global &&
over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
}
fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool {
match (left, right) {
(&AngleBracketedParameters(ref left), &AngleBracketedParameters(ref right)) => {
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) &&
over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) &&
over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
}
(&ParenthesizedParameters(ref left), &ParenthesizedParameters(ref right)) => {
over(&left.inputs, &right.inputs, |l, r| self.eq_ty(l, r)) &&
both(&left.output, &right.output, |l, r| self.eq_ty(l, r))
}
(&AngleBracketedParameters(_), &ParenthesizedParameters(_)) |
(&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => {
false
}
}
}
fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool {
2016-02-06 19:13:25 +00:00
// The == of idents doesn't work with different contexts,
// we have to be explicit about hygiene
left.name.as_str() == right.name.as_str() &&
self.eq_path_parameters(&left.parameters, &right.parameters)
2016-02-06 19:13:25 +00:00
}
fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool {
left.ty.node == right.ty.node && left.position == right.position
}
fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
match (&left.node, &right.node) {
(&TyVec(ref l_vec), &TyVec(ref r_vec)) => self.eq_ty(l_vec, r_vec),
2016-02-09 16:10:50 +00:00
(&TyFixedLengthVec(ref lt, ref ll), &TyFixedLengthVec(ref rt, ref rl)) => {
self.eq_ty(lt, rt) && self.eq_expr(ll, rl)
}
(&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
(&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
2016-02-06 19:13:25 +00:00
}
(&TyPath(ref lq, ref l_path), &TyPath(ref rq, ref r_path)) => {
both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(l_path, r_path)
2016-02-06 19:13:25 +00:00
}
2016-02-09 16:10:50 +00:00
(&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
2016-02-06 19:13:25 +00:00
(&TyInfer, &TyInfer) => true,
_ => false,
}
}
fn eq_type_binding(&self, left: &TypeBinding, right: &TypeBinding) -> bool {
left.name == right.name && self.eq_ty(&left.ty, &right.ty)
}
2016-02-06 19:13:25 +00:00
}
fn swap_binop<'a>(binop: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOp_, &'a Expr, &'a Expr)> {
match binop {
BiAdd |
BiMul |
BiBitXor |
BiBitAnd |
BiEq |
BiNe |
BiBitOr => Some((binop, rhs, lhs)),
BiLt => Some((BiGt, rhs, lhs)),
BiLe => Some((BiGe, rhs, lhs)),
BiGe => Some((BiLe, rhs, lhs)),
BiGt => Some((BiLt, rhs, lhs)),
BiShl | BiShr | BiRem | BiSub | BiDiv | BiAnd | BiOr => None,
}
}
2016-02-06 19:13:25 +00:00
/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`.
fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
where F: FnMut(&X, &X) -> bool
{
l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
}
/// Check if two slices are equal as per `eq_fn`.
fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
where F: FnMut(&X, &X) -> bool
{
left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
}
2016-02-09 14:18:27 +00:00
/// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this
/// trait would consider IDs and spans.
///
/// All expressions kind are hashed, but some might have a weaker hash.
2016-02-09 14:18:27 +00:00
pub struct SpanlessHash<'a, 'tcx: 'a> {
/// Context used to evaluate constant expressions.
cx: &'a LateContext<'a, 'tcx>,
s: SipHasher,
}
impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
2016-02-24 16:38:57 +00:00
SpanlessHash {
cx: cx,
s: SipHasher::new(),
}
2016-02-09 14:18:27 +00:00
}
pub fn finish(&self) -> u64 {
self.s.finish()
}
pub fn hash_block(&mut self, b: &Block) {
for s in &b.stmts {
self.hash_stmt(s);
}
if let Some(ref e) = b.expr {
self.hash_expr(e);
}
b.rules.hash(&mut self.s);
}
pub fn hash_expr(&mut self, e: &Expr) {
if let Some(e) = constant(self.cx, e) {
return e.hash(&mut self.s);
}
match e.node {
ExprAddrOf(m, ref e) => {
let c: fn(_, _) -> _ = ExprAddrOf;
c.hash(&mut self.s);
m.hash(&mut self.s);
self.hash_expr(e);
}
ExprAgain(i) => {
let c: fn(_) -> _ = ExprAgain;
c.hash(&mut self.s);
if let Some(i) = i {
self.hash_name(&i.node);
2016-02-09 14:18:27 +00:00
}
}
ExprAssign(ref l, ref r) => {
let c: fn(_, _) -> _ = ExprAssign;
c.hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
}
ExprAssignOp(ref o, ref l, ref r) => {
let c: fn(_, _, _) -> _ = ExprAssignOp;
c.hash(&mut self.s);
o.hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
}
ExprBlock(ref b) => {
let c: fn(_) -> _ = ExprBlock;
c.hash(&mut self.s);
self.hash_block(b);
}
ExprBinary(op, ref l, ref r) => {
let c: fn(_, _, _) -> _ = ExprBinary;
c.hash(&mut self.s);
op.node.hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
}
ExprBreak(i) => {
let c: fn(_) -> _ = ExprBreak;
c.hash(&mut self.s);
if let Some(i) = i {
self.hash_name(&i.node);
2016-02-09 14:18:27 +00:00
}
}
ExprBox(ref e) => {
let c: fn(_) -> _ = ExprBox;
c.hash(&mut self.s);
self.hash_expr(e);
}
ExprCall(ref fun, ref args) => {
let c: fn(_, _) -> _ = ExprCall;
c.hash(&mut self.s);
self.hash_expr(fun);
self.hash_exprs(args);
}
ExprCast(ref e, ref _ty) => {
let c: fn(_, _) -> _ = ExprCast;
c.hash(&mut self.s);
self.hash_expr(e);
// TODO: _ty
}
ExprClosure(cap, _, ref b, _) => {
let c: fn(_, _, _, _) -> _ = ExprClosure;
2016-02-09 14:18:27 +00:00
c.hash(&mut self.s);
cap.hash(&mut self.s);
self.hash_block(b);
}
ExprField(ref e, ref f) => {
let c: fn(_, _) -> _ = ExprField;
c.hash(&mut self.s);
self.hash_expr(e);
self.hash_name(&f.node);
}
ExprIndex(ref a, ref i) => {
let c: fn(_, _) -> _ = ExprIndex;
c.hash(&mut self.s);
self.hash_expr(a);
self.hash_expr(i);
}
2016-03-20 20:24:18 +00:00
ExprInlineAsm(..) => {
let c: fn(_, _, _) -> _ = ExprInlineAsm;
2016-02-09 14:18:27 +00:00
c.hash(&mut self.s);
}
ExprIf(ref cond, ref t, ref e) => {
let c: fn(_, _, _) -> _ = ExprIf;
c.hash(&mut self.s);
self.hash_expr(cond);
self.hash_block(t);
if let Some(ref e) = *e {
self.hash_expr(e);
}
}
ExprLit(ref l) => {
let c: fn(_) -> _ = ExprLit;
c.hash(&mut self.s);
l.hash(&mut self.s);
2016-02-24 16:38:57 +00:00
}
2016-02-09 14:18:27 +00:00
ExprLoop(ref b, ref i) => {
let c: fn(_, _) -> _ = ExprLoop;
c.hash(&mut self.s);
self.hash_block(b);
if let Some(i) = *i {
self.hash_name(&i.node);
2016-02-09 14:18:27 +00:00
}
}
ExprMatch(ref e, ref arms, ref s) => {
let c: fn(_, _, _) -> _ = ExprMatch;
c.hash(&mut self.s);
self.hash_expr(e);
for arm in arms {
// TODO: arm.pat?
if let Some(ref e) = arm.guard {
self.hash_expr(e);
}
self.hash_expr(&arm.body);
}
s.hash(&mut self.s);
}
ExprMethodCall(ref name, ref _tys, ref args) => {
let c: fn(_, _, _) -> _ = ExprMethodCall;
c.hash(&mut self.s);
self.hash_name(&name.node);
self.hash_exprs(args);
}
ExprRepeat(ref e, ref l) => {
let c: fn(_, _) -> _ = ExprRepeat;
c.hash(&mut self.s);
self.hash_expr(e);
self.hash_expr(l);
}
ExprRet(ref e) => {
let c: fn(_) -> _ = ExprRet;
c.hash(&mut self.s);
if let Some(ref e) = *e {
self.hash_expr(e);
}
}
ExprPath(ref _qself, ref subpath) => {
let c: fn(_, _) -> _ = ExprPath;
c.hash(&mut self.s);
self.hash_path(subpath);
}
ExprStruct(ref path, ref fields, ref expr) => {
let c: fn(_, _, _) -> _ = ExprStruct;
c.hash(&mut self.s);
self.hash_path(path);
for f in fields {
self.hash_name(&f.name.node);
self.hash_expr(&f.expr);
}
if let Some(ref e) = *expr {
self.hash_expr(e);
}
}
ExprTup(ref tup) => {
let c: fn(_) -> _ = ExprTup;
c.hash(&mut self.s);
self.hash_exprs(tup);
2016-02-24 16:38:57 +00:00
}
2016-02-09 14:18:27 +00:00
ExprTupField(ref le, li) => {
let c: fn(_, _) -> _ = ExprTupField;
c.hash(&mut self.s);
self.hash_expr(le);
li.node.hash(&mut self.s);
}
ExprType(ref e, ref _ty) => {
2016-02-09 14:18:27 +00:00
let c: fn(_, _) -> _ = ExprType;
c.hash(&mut self.s);
self.hash_expr(e);
// TODO: _ty
2016-02-09 14:18:27 +00:00
}
ExprUnary(lop, ref le) => {
let c: fn(_, _) -> _ = ExprUnary;
c.hash(&mut self.s);
lop.hash(&mut self.s);
self.hash_expr(le);
}
ExprVec(ref v) => {
let c: fn(_) -> _ = ExprVec;
c.hash(&mut self.s);
self.hash_exprs(v);
2016-02-24 16:38:57 +00:00
}
2016-02-09 14:18:27 +00:00
ExprWhile(ref cond, ref b, l) => {
let c: fn(_, _, _) -> _ = ExprWhile;
c.hash(&mut self.s);
self.hash_expr(cond);
self.hash_block(b);
if let Some(l) = l {
self.hash_name(&l.node);
2016-02-09 14:18:27 +00:00
}
}
}
}
pub fn hash_exprs(&mut self, e: &[P<Expr>]) {
for e in e {
self.hash_expr(e);
}
}
pub fn hash_name(&mut self, n: &Name) {
n.as_str().hash(&mut self.s);
}
pub fn hash_path(&mut self, p: &Path) {
p.global.hash(&mut self.s);
for p in &p.segments {
self.hash_name(&p.name);
2016-02-09 14:18:27 +00:00
}
}
pub fn hash_stmt(&mut self, b: &Stmt) {
match b.node {
StmtDecl(ref decl, _) => {
2016-02-09 14:18:27 +00:00
let c: fn(_, _) -> _ = StmtDecl;
c.hash(&mut self.s);
if let DeclLocal(ref local) = decl.node {
if let Some(ref init) = local.init {
self.hash_expr(init);
}
}
2016-02-09 14:18:27 +00:00
}
StmtExpr(ref expr, _) => {
let c: fn(_, _) -> _ = StmtExpr;
c.hash(&mut self.s);
self.hash_expr(expr);
}
StmtSemi(ref expr, _) => {
let c: fn(_, _) -> _ = StmtSemi;
c.hash(&mut self.s);
self.hash_expr(expr);
}
}
}
}