]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/hir_utils.rs
Rustup to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
[rust.git] / clippy_lints / src / utils / hir_utils.rs
1 use consts::constant;
2 use rustc::lint::*;
3 use rustc::hir::*;
4 use std::hash::{Hash, Hasher};
5 use std::collections::hash_map::DefaultHasher;
6 use syntax::ast::Name;
7 use syntax::ptr::P;
8 use utils::differing_macro_contexts;
9
10 /// Type used to check whether two ast are the same. This is different from the operator
11 /// `==` on ast types as this operator would compare true equality with ID and span.
12 ///
13 /// Note that some expressions kinds are not considered but could be added.
14 pub struct SpanlessEq<'a, 'tcx: 'a> {
15     /// Context used to evaluate constant expressions.
16     cx: &'a LateContext<'a, 'tcx>,
17     /// If is true, never consider as equal expressions containing function calls.
18     ignore_fn: bool,
19 }
20
21 impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
22     pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
23         SpanlessEq {
24             cx: cx,
25             ignore_fn: false,
26         }
27     }
28
29     pub fn ignore_fn(self) -> Self {
30         SpanlessEq {
31             cx: self.cx,
32             ignore_fn: true,
33         }
34     }
35
36     /// Check whether two statements are the same.
37     pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool {
38         match (&left.node, &right.node) {
39             (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => {
40                 if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) {
41                     both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
42                 } else {
43                     false
44                 }
45             },
46             (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) |
47             (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r),
48             _ => false,
49         }
50     }
51
52     /// Check whether two blocks are the same.
53     pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
54         over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
55         both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
56     }
57
58     pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
59         if self.ignore_fn && differing_macro_contexts(left.span, right.span) {
60             return false;
61         }
62
63         if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) {
64             if l == r {
65                 return true;
66             }
67         }
68
69         match (&left.node, &right.node) {
70             (&ExprAddrOf(l_mut, ref le), &ExprAddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re),
71             (&ExprAgain(li), &ExprAgain(ri)) => {
72                 both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str())
73             },
74             (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr),
75             (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
76                 lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
77             },
78             (&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
79             (&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
80                 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) ||
81                 swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
82                     l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
83                 })
84             },
85             (&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => {
86                 both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str()) &&
87                 both(le, re, |l, r| self.eq_expr(l, r))
88             },
89             (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
90             (&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
91                 !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
92             },
93             (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) |
94             (&ExprType(ref lx, ref lt), &ExprType(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt),
95             (&ExprField(ref l_f_exp, ref l_f_ident), &ExprField(ref r_f_exp, ref r_f_ident)) => {
96                 l_f_ident.node == r_f_ident.node && self.eq_expr(l_f_exp, r_f_exp)
97             },
98             (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
99             (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => {
100                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
101             },
102             (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
103             (&ExprLoop(ref lb, ref ll, ref lls), &ExprLoop(ref rb, ref rl, ref rls)) => {
104                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str())
105             },
106             (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
107                 ls == rs && self.eq_expr(le, re) &&
108                 over(la, ra, |l, r| {
109                     self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
110                     over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
111                 })
112             },
113             (&ExprMethodCall(ref l_path, _, ref l_args),
114              &ExprMethodCall(ref r_path, _, ref r_args)) => {
115                 !self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args)
116             },
117             (&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => {
118                 self.eq_expr(le, re) &&
119                 self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
120             },
121             (&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
122             (&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r),
123             (&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
124                 self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
125                 over(lf, rf, |l, r| self.eq_field(l, r))
126             },
127             (&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
128             (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
129             (&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
130             (&ExprArray(ref l), &ExprArray(ref r)) => self.eq_exprs(l, r),
131             (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => {
132                 self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str())
133             },
134             _ => false,
135         }
136     }
137
138     fn eq_exprs(&self, left: &P<[Expr]>, right: &P<[Expr]>) -> bool {
139         over(left, right, |l, r| self.eq_expr(l, r))
140     }
141
142     fn eq_field(&self, left: &Field, right: &Field) -> bool {
143         left.name.node == right.name.node && self.eq_expr(&left.expr, &right.expr)
144     }
145
146     fn eq_lifetime(&self, left: &Lifetime, right: &Lifetime) -> bool {
147         left.name == right.name
148     }
149
150     /// Check whether two patterns are the same.
151     pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool {
152         match (&left.node, &right.node) {
153             (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
154             (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
155                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
156             },
157             (&PatKind::Binding(ref lb, _, ref li, ref lp), &PatKind::Binding(ref rb, _, ref ri, ref rp)) => {
158                 lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
159             },
160             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
161             (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
162             (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
163                 ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
164             },
165             (&PatKind::Range(ref ls, ref le, ref li), &PatKind::Range(ref rs, ref re, ref ri)) => {
166                 self.eq_expr(ls, rs) && self.eq_expr(le, re) && (*li == *ri)
167             },
168             (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
169             (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
170                 over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) &&
171                 both(li, ri, |l, r| self.eq_pat(l, r))
172             },
173             (&PatKind::Wild, &PatKind::Wild) => true,
174             _ => false,
175         }
176     }
177
178     fn eq_qpath(&self, left: &QPath, right: &QPath) -> bool {
179         match (left, right) {
180             (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
181                 both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
182             },
183             (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
184                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
185             },
186             _ => false,
187         }
188     }
189
190     fn eq_path(&self, left: &Path, right: &Path) -> bool {
191         left.is_global() == right.is_global() &&
192         over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
193     }
194
195     fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool {
196         match (left, right) {
197             (&AngleBracketedParameters(ref left), &AngleBracketedParameters(ref right)) => {
198                 over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) &&
199                 over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) &&
200                 over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
201             },
202             (&ParenthesizedParameters(ref left), &ParenthesizedParameters(ref right)) => {
203                 over(&left.inputs, &right.inputs, |l, r| self.eq_ty(l, r)) &&
204                 both(&left.output, &right.output, |l, r| self.eq_ty(l, r))
205             },
206             (&AngleBracketedParameters(_), &ParenthesizedParameters(_)) |
207             (&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => false,
208         }
209     }
210
211     fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool {
212         // The == of idents doesn't work with different contexts,
213         // we have to be explicit about hygiene
214         left.name.as_str() == right.name.as_str() && self.eq_path_parameters(&left.parameters, &right.parameters)
215     }
216
217     fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
218         match (&left.node, &right.node) {
219             (&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
220             (&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => {
221                 self.eq_ty(lt, rt) &&
222                 self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
223             },
224             (&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
225             (&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
226                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
227             },
228             (&TyPath(ref l), &TyPath(ref r)) => self.eq_qpath(l, r),
229             (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
230             (&TyInfer, &TyInfer) => true,
231             _ => false,
232         }
233     }
234
235     fn eq_type_binding(&self, left: &TypeBinding, right: &TypeBinding) -> bool {
236         left.name == right.name && self.eq_ty(&left.ty, &right.ty)
237     }
238 }
239
240 fn swap_binop<'a>(binop: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOp_, &'a Expr, &'a Expr)> {
241     match binop {
242         BiAdd | BiMul | BiBitXor | BiBitAnd | BiEq | BiNe | BiBitOr => Some((binop, rhs, lhs)),
243         BiLt => Some((BiGt, rhs, lhs)),
244         BiLe => Some((BiGe, rhs, lhs)),
245         BiGe => Some((BiLe, rhs, lhs)),
246         BiGt => Some((BiLt, rhs, lhs)),
247         BiShl | BiShr | BiRem | BiSub | BiDiv | BiAnd | BiOr => None,
248     }
249 }
250
251 /// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`.
252 fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
253     where F: FnMut(&X, &X) -> bool
254 {
255     l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
256 }
257
258 /// Check if two slices are equal as per `eq_fn`.
259 fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
260     where F: FnMut(&X, &X) -> bool
261 {
262     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
263 }
264
265
266 /// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this
267 /// trait would consider IDs and spans.
268 ///
269 /// All expressions kind are hashed, but some might have a weaker hash.
270 pub struct SpanlessHash<'a, 'tcx: 'a> {
271     /// Context used to evaluate constant expressions.
272     cx: &'a LateContext<'a, 'tcx>,
273     s: DefaultHasher,
274 }
275
276 impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
277     pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
278         SpanlessHash {
279             cx: cx,
280             s: DefaultHasher::new(),
281         }
282     }
283
284     pub fn finish(&self) -> u64 {
285         self.s.finish()
286     }
287
288     pub fn hash_block(&mut self, b: &Block) {
289         for s in &b.stmts {
290             self.hash_stmt(s);
291         }
292
293         if let Some(ref e) = b.expr {
294             self.hash_expr(e);
295         }
296
297         b.rules.hash(&mut self.s);
298     }
299
300     pub fn hash_expr(&mut self, e: &Expr) {
301         if let Some(e) = constant(self.cx, e) {
302             return e.hash(&mut self.s);
303         }
304
305         match e.node {
306             ExprAddrOf(m, ref e) => {
307                 let c: fn(_, _) -> _ = ExprAddrOf;
308                 c.hash(&mut self.s);
309                 m.hash(&mut self.s);
310                 self.hash_expr(e);
311             },
312             ExprAgain(i) => {
313                 let c: fn(_) -> _ = ExprAgain;
314                 c.hash(&mut self.s);
315                 if let Some(i) = i.ident {
316                     self.hash_name(&i.node.name);
317                 }
318             },
319             ExprAssign(ref l, ref r) => {
320                 let c: fn(_, _) -> _ = ExprAssign;
321                 c.hash(&mut self.s);
322                 self.hash_expr(l);
323                 self.hash_expr(r);
324             },
325             ExprAssignOp(ref o, ref l, ref r) => {
326                 let c: fn(_, _, _) -> _ = ExprAssignOp;
327                 c.hash(&mut self.s);
328                 o.hash(&mut self.s);
329                 self.hash_expr(l);
330                 self.hash_expr(r);
331             },
332             ExprBlock(ref b) => {
333                 let c: fn(_) -> _ = ExprBlock;
334                 c.hash(&mut self.s);
335                 self.hash_block(b);
336             },
337             ExprBinary(op, ref l, ref r) => {
338                 let c: fn(_, _, _) -> _ = ExprBinary;
339                 c.hash(&mut self.s);
340                 op.node.hash(&mut self.s);
341                 self.hash_expr(l);
342                 self.hash_expr(r);
343             },
344             ExprBreak(i, ref j) => {
345                 let c: fn(_, _) -> _ = ExprBreak;
346                 c.hash(&mut self.s);
347                 if let Some(i) = i.ident {
348                     self.hash_name(&i.node.name);
349                 }
350                 if let Some(ref j) = *j {
351                     self.hash_expr(&*j);
352                 }
353             },
354             ExprBox(ref e) => {
355                 let c: fn(_) -> _ = ExprBox;
356                 c.hash(&mut self.s);
357                 self.hash_expr(e);
358             },
359             ExprCall(ref fun, ref args) => {
360                 let c: fn(_, _) -> _ = ExprCall;
361                 c.hash(&mut self.s);
362                 self.hash_expr(fun);
363                 self.hash_exprs(args);
364             },
365             ExprCast(ref e, ref _ty) => {
366                 let c: fn(_, _) -> _ = ExprCast;
367                 c.hash(&mut self.s);
368                 self.hash_expr(e);
369                 // TODO: _ty
370             },
371             ExprClosure(cap, _, eid, _) => {
372                 let c: fn(_, _, _, _) -> _ = ExprClosure;
373                 c.hash(&mut self.s);
374                 cap.hash(&mut self.s);
375                 self.hash_expr(&self.cx.tcx.hir.body(eid).value);
376             },
377             ExprField(ref e, ref f) => {
378                 let c: fn(_, _) -> _ = ExprField;
379                 c.hash(&mut self.s);
380                 self.hash_expr(e);
381                 self.hash_name(&f.node);
382             },
383             ExprIndex(ref a, ref i) => {
384                 let c: fn(_, _) -> _ = ExprIndex;
385                 c.hash(&mut self.s);
386                 self.hash_expr(a);
387                 self.hash_expr(i);
388             },
389             ExprInlineAsm(..) => {
390                 let c: fn(_, _, _) -> _ = ExprInlineAsm;
391                 c.hash(&mut self.s);
392             },
393             ExprIf(ref cond, ref t, ref e) => {
394                 let c: fn(_, _, _) -> _ = ExprIf;
395                 c.hash(&mut self.s);
396                 self.hash_expr(cond);
397                 self.hash_expr(&**t);
398                 if let Some(ref e) = *e {
399                     self.hash_expr(e);
400                 }
401             },
402             ExprLit(ref l) => {
403                 let c: fn(_) -> _ = ExprLit;
404                 c.hash(&mut self.s);
405                 l.hash(&mut self.s);
406             },
407             ExprLoop(ref b, ref i, _) => {
408                 let c: fn(_, _, _) -> _ = ExprLoop;
409                 c.hash(&mut self.s);
410                 self.hash_block(b);
411                 if let Some(i) = *i {
412                     self.hash_name(&i.node);
413                 }
414             },
415             ExprMatch(ref e, ref arms, ref s) => {
416                 let c: fn(_, _, _) -> _ = ExprMatch;
417                 c.hash(&mut self.s);
418                 self.hash_expr(e);
419
420                 for arm in arms {
421                     // TODO: arm.pat?
422                     if let Some(ref e) = arm.guard {
423                         self.hash_expr(e);
424                     }
425                     self.hash_expr(&arm.body);
426                 }
427
428                 s.hash(&mut self.s);
429             },
430             ExprMethodCall(ref path, ref _tys, ref args) => {
431                 let c: fn(_, _, _) -> _ = ExprMethodCall;
432                 c.hash(&mut self.s);
433                 self.hash_name(&path.name);
434                 self.hash_exprs(args);
435             },
436             ExprRepeat(ref e, l_id) => {
437                 let c: fn(_, _) -> _ = ExprRepeat;
438                 c.hash(&mut self.s);
439                 self.hash_expr(e);
440                 self.hash_expr(&self.cx.tcx.hir.body(l_id).value);
441             },
442             ExprRet(ref e) => {
443                 let c: fn(_) -> _ = ExprRet;
444                 c.hash(&mut self.s);
445                 if let Some(ref e) = *e {
446                     self.hash_expr(e);
447                 }
448             },
449             ExprPath(ref qpath) => {
450                 let c: fn(_) -> _ = ExprPath;
451                 c.hash(&mut self.s);
452                 self.hash_qpath(qpath);
453             },
454             ExprStruct(ref path, ref fields, ref expr) => {
455                 let c: fn(_, _, _) -> _ = ExprStruct;
456                 c.hash(&mut self.s);
457
458                 self.hash_qpath(path);
459
460                 for f in fields {
461                     self.hash_name(&f.name.node);
462                     self.hash_expr(&f.expr);
463                 }
464
465                 if let Some(ref e) = *expr {
466                     self.hash_expr(e);
467                 }
468             },
469             ExprTup(ref tup) => {
470                 let c: fn(_) -> _ = ExprTup;
471                 c.hash(&mut self.s);
472                 self.hash_exprs(tup);
473             },
474             ExprTupField(ref le, li) => {
475                 let c: fn(_, _) -> _ = ExprTupField;
476                 c.hash(&mut self.s);
477
478                 self.hash_expr(le);
479                 li.node.hash(&mut self.s);
480             },
481             ExprType(ref e, ref _ty) => {
482                 let c: fn(_, _) -> _ = ExprType;
483                 c.hash(&mut self.s);
484                 self.hash_expr(e);
485                 // TODO: _ty
486             },
487             ExprUnary(lop, ref le) => {
488                 let c: fn(_, _) -> _ = ExprUnary;
489                 c.hash(&mut self.s);
490
491                 lop.hash(&mut self.s);
492                 self.hash_expr(le);
493             },
494             ExprArray(ref v) => {
495                 let c: fn(_) -> _ = ExprArray;
496                 c.hash(&mut self.s);
497
498                 self.hash_exprs(v);
499             },
500             ExprWhile(ref cond, ref b, l) => {
501                 let c: fn(_, _, _) -> _ = ExprWhile;
502                 c.hash(&mut self.s);
503
504                 self.hash_expr(cond);
505                 self.hash_block(b);
506                 if let Some(l) = l {
507                     self.hash_name(&l.node);
508                 }
509             },
510         }
511     }
512
513     pub fn hash_exprs(&mut self, e: &P<[Expr]>) {
514         for e in e {
515             self.hash_expr(e);
516         }
517     }
518
519     pub fn hash_name(&mut self, n: &Name) {
520         n.as_str().hash(&mut self.s);
521     }
522
523     pub fn hash_qpath(&mut self, p: &QPath) {
524         match *p {
525             QPath::Resolved(_, ref path) => {
526                 self.hash_path(path);
527             },
528             QPath::TypeRelative(_, ref path) => {
529                 self.hash_name(&path.name);
530             },
531         }
532         // self.cx.tables.qpath_def(p, id).hash(&mut self.s);
533     }
534
535     pub fn hash_path(&mut self, p: &Path) {
536         p.is_global().hash(&mut self.s);
537         for p in &p.segments {
538             self.hash_name(&p.name);
539         }
540     }
541
542     pub fn hash_stmt(&mut self, b: &Stmt) {
543         match b.node {
544             StmtDecl(ref decl, _) => {
545                 let c: fn(_, _) -> _ = StmtDecl;
546                 c.hash(&mut self.s);
547
548                 if let DeclLocal(ref local) = decl.node {
549                     if let Some(ref init) = local.init {
550                         self.hash_expr(init);
551                     }
552                 }
553             },
554             StmtExpr(ref expr, _) => {
555                 let c: fn(_, _) -> _ = StmtExpr;
556                 c.hash(&mut self.s);
557                 self.hash_expr(expr);
558             },
559             StmtSemi(ref expr, _) => {
560                 let c: fn(_, _) -> _ = StmtSemi;
561                 c.hash(&mut self.s);
562                 self.hash_expr(expr);
563             },
564         }
565     }
566 }