diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index e380a7bfbfebe..838be076a0b62 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -487,14 +487,6 @@ impl Definitions {
         self.node_to_hir_id[node_id]
     }
 
-    pub fn find_node_for_hir_id(&self, hir_id: hir::HirId) -> ast::NodeId {
-        self.node_to_hir_id
-            .iter()
-            .position(|x| *x == hir_id)
-            .map(|idx| ast::NodeId::new(idx))
-            .unwrap()
-    }
-
     #[inline]
     pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId {
         let space_index = def_index.address_space().index();
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 13fff3aa34274..5a059b6a219a2 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -10,7 +10,7 @@
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use hir::{self, PatKind};
+use hir::{self, HirId, PatKind};
 use syntax::ast;
 use syntax::codemap::Spanned;
 use syntax_pos::Span;
@@ -91,11 +91,11 @@ impl hir::Pat {
     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
     /// `match foo() { Some(a) => (), None => () }`
     pub fn each_binding<F>(&self, mut f: F)
-        where F: FnMut(hir::BindingAnnotation, ast::NodeId, Span, &Spanned<ast::Name>),
+        where F: FnMut(hir::BindingAnnotation, HirId, Span, &Spanned<ast::Name>),
     {
         self.walk(|p| {
             if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
-                f(binding_mode, p.id, p.span, pth);
+                f(binding_mode, p.hir_id, p.span, pth);
             }
             true
         });
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index fd6c2f652f04b..ddbc03292f644 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -608,9 +608,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     fn walk_local(&mut self, local: &hir::Local) {
         match local.init {
             None => {
-                let delegate = &mut self.delegate;
-                local.pat.each_binding(|_, id, span, _| {
-                    delegate.decl_without_init(id, span);
+                local.pat.each_binding(|_, hir_id, span, _| {
+                    let node_id = self.mc.tcx.hir.hir_to_node_id(hir_id);
+                    self.delegate.decl_without_init(node_id, span);
                 })
             }
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 3633d6f9934ec..82686bc737bc8 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -110,7 +110,7 @@ use hir::def::*;
 use ty::{self, TyCtxt};
 use lint;
 use errors::Applicability;
-use util::nodemap::{NodeMap, NodeSet};
+use util::nodemap::{NodeMap, HirIdMap, HirIdSet};
 
 use std::collections::VecDeque;
 use std::{fmt, u32};
@@ -122,7 +122,7 @@ use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 
-use hir::Expr;
+use hir::{Expr, HirId};
 use hir;
 use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
@@ -236,19 +236,19 @@ fn invalid_node() -> LiveNode { LiveNode(u32::MAX) }
 
 struct CaptureInfo {
     ln: LiveNode,
-    var_nid: NodeId
+    var_hid: HirId
 }
 
 #[derive(Copy, Clone, Debug)]
 struct LocalInfo {
-    id: NodeId,
+    id: HirId,
     name: ast::Name,
     is_shorthand: bool,
 }
 
 #[derive(Copy, Clone, Debug)]
 enum VarKind {
-    Arg(NodeId, ast::Name),
+    Arg(HirId, ast::Name),
     Local(LocalInfo),
     CleanExit
 }
@@ -258,8 +258,8 @@ struct IrMaps<'a, 'tcx: 'a> {
 
     num_live_nodes: usize,
     num_vars: usize,
-    live_node_map: NodeMap<LiveNode>,
-    variable_map: NodeMap<Variable>,
+    live_node_map: HirIdMap<LiveNode>,
+    variable_map: HirIdMap<Variable>,
     capture_info_map: NodeMap<Rc<Vec<CaptureInfo>>>,
     var_kinds: Vec<VarKind>,
     lnks: Vec<LiveNodeKind>,
@@ -271,8 +271,8 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
             tcx,
             num_live_nodes: 0,
             num_vars: 0,
-            live_node_map: NodeMap(),
-            variable_map: NodeMap(),
+            live_node_map: HirIdMap(),
+            variable_map: HirIdMap(),
             capture_info_map: NodeMap(),
             var_kinds: Vec::new(),
             lnks: Vec::new(),
@@ -290,11 +290,11 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
         ln
     }
 
-    fn add_live_node_for_node(&mut self, node_id: NodeId, lnk: LiveNodeKind) {
+    fn add_live_node_for_node(&mut self, hir_id: HirId, lnk: LiveNodeKind) {
         let ln = self.add_live_node(lnk);
-        self.live_node_map.insert(node_id, ln);
+        self.live_node_map.insert(hir_id, ln);
 
-        debug!("{:?} is node {}", ln, node_id);
+        debug!("{:?} is node {:?}", ln, hir_id);
     }
 
     fn add_variable(&mut self, vk: VarKind) -> Variable {
@@ -314,11 +314,11 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
         v
     }
 
-    fn variable(&self, node_id: NodeId, span: Span) -> Variable {
-        match self.variable_map.get(&node_id) {
+    fn variable(&self, hir_id: HirId, span: Span) -> Variable {
+        match self.variable_map.get(&hir_id) {
             Some(&var) => var,
             None => {
-                span_bug!(span, "no variable registered for id {}", node_id);
+                span_bug!(span, "no variable registered for id {:?}", hir_id);
             }
         }
     }
@@ -374,10 +374,10 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
     let body = ir.tcx.hir.body(body_id);
 
     for arg in &body.arguments {
-        arg.pat.each_binding(|_bm, arg_id, _x, path1| {
-            debug!("adding argument {}", arg_id);
+        arg.pat.each_binding(|_bm, hir_id, _x, path1| {
+            debug!("adding argument {:?}", hir_id);
             let name = path1.node;
-            fn_maps.add_variable(Arg(arg_id, name));
+            fn_maps.add_variable(Arg(hir_id, name));
         })
     };
 
@@ -397,11 +397,7 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
 fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
     // For struct patterns, take note of which fields used shorthand
     // (`x` rather than `x: x`).
-    //
-    // FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be
-    // phased out in favor of `HirId`s; however, we need to match the signature of
-    // `each_binding`, which uses `NodeIds`.
-    let mut shorthand_field_ids = NodeSet();
+    let mut shorthand_field_ids = HirIdSet();
     let mut pats = VecDeque::new();
     pats.push_back(pat);
     while let Some(pat) = pats.pop_front() {
@@ -413,7 +409,7 @@ fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
             Struct(_, ref fields, _) => {
                 for field in fields {
                     if field.node.is_shorthand {
-                        shorthand_field_ids.insert(field.node.pat.id);
+                        shorthand_field_ids.insert(field.node.pat.hir_id);
                     }
                 }
             }
@@ -434,13 +430,13 @@ fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P<hir::Pat>) {
         }
     }
 
-    pat.each_binding(|_bm, p_id, _sp, path1| {
+    pat.each_binding(|_bm, hir_id, _sp, path1| {
         let name = path1.node;
-        ir.add_live_node_for_node(p_id, VarDefNode(path1.span));
+        ir.add_live_node_for_node(hir_id, VarDefNode(path1.span));
         ir.add_variable(Local(LocalInfo {
-            id: p_id,
+            id: hir_id,
             name,
-            is_shorthand: shorthand_field_ids.contains(&p_id)
+            is_shorthand: shorthand_field_ids.contains(&hir_id)
         }));
     });
 }
@@ -463,14 +459,14 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
       hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
         debug!("expr {}: path that leads to {:?}", expr.id, path.def);
         if let Def::Local(..) = path.def {
-            ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
+            ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
         }
         intravisit::walk_expr(ir, expr);
       }
       hir::ExprClosure(..) => {
         // Interesting control flow (for loops can contain labeled
         // breaks or continues)
-        ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
+        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
 
         // Make a live_node for each captured variable, with the span
         // being the location that the variable is used.  This results
@@ -481,8 +477,8 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
             for fv in freevars {
                 if let Def::Local(rv) = fv.def {
                     let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
-                    call_caps.push(CaptureInfo {ln: fv_ln,
-                                                var_nid: rv});
+                    let var_hid = ir.tcx.hir.node_to_hir_id(rv);
+                    call_caps.push(CaptureInfo { ln: fv_ln, var_hid });
                 }
             }
         });
@@ -493,11 +489,11 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
 
       // live nodes required for interesting control flow:
       hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) => {
-        ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
+        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
       hir::ExprBinary(op, ..) if op.node.is_lazy() => {
-        ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
+        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
 
@@ -590,8 +586,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn live_node(&self, node_id: NodeId, span: Span) -> LiveNode {
-        match self.ir.live_node_map.get(&node_id) {
+    fn live_node(&self, hir_id: HirId, span: Span) -> LiveNode {
+        match self.ir.live_node_map.get(&hir_id) {
           Some(&ln) => ln,
           None => {
             // This must be a mismatch between the ir_map construction
@@ -600,28 +596,28 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             // creating liveness nodes for.
             span_bug!(
                 span,
-                "no live node registered for node {}",
-                node_id);
+                "no live node registered for node {:?}",
+                hir_id);
           }
         }
     }
 
-    fn variable(&self, node_id: NodeId, span: Span) -> Variable {
-        self.ir.variable(node_id, span)
+    fn variable(&self, hir_id: HirId, span: Span) -> Variable {
+        self.ir.variable(hir_id, span)
     }
 
     fn pat_bindings<F>(&mut self, pat: &hir::Pat, mut f: F) where
-        F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
+        F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId),
     {
-        pat.each_binding(|_bm, p_id, sp, n| {
-            let ln = self.live_node(p_id, sp);
-            let var = self.variable(p_id, n.span);
-            f(self, ln, var, n.span, p_id);
+        pat.each_binding(|_bm, hir_id, sp, n| {
+            let ln = self.live_node(hir_id, sp);
+            let var = self.variable(hir_id, n.span);
+            f(self, ln, var, n.span, hir_id);
         })
     }
 
     fn arm_pats_bindings<F>(&mut self, pat: Option<&hir::Pat>, f: F) where
-        F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
+        F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId),
     {
         if let Some(pat) = pat {
             self.pat_bindings(pat, f);
@@ -927,7 +923,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         match expr.node {
           // Interesting cases with control flow or which gen/kill
           hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-              self.access_path(expr.id, path, succ, ACC_READ | ACC_USE)
+              self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
           }
 
           hir::ExprField(ref e, _) => {
@@ -937,11 +933,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           hir::ExprClosure(.., blk_id, _, _) => {
               debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id));
 
-              /*
-              The next-node for a break is the successor of the entire
-              loop. The next-node for a continue is the top of this loop.
-              */
-              let node = self.live_node(expr.id, expr.span);
+              // The next-node for a break is the successor of the entire
+              // loop. The next-node for a continue is the top of this loop.
+              let node = self.live_node(expr.hir_id, expr.span);
 
               let break_ln = succ;
               let cont_ln = node;
@@ -958,7 +952,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               };
               caps.iter().rev().fold(succ, |succ, cap| {
                   self.init_from_succ(cap.ln, succ);
-                  let var = self.variable(cap.var_nid, expr.span);
+                  let var = self.variable(cap.var_hid, expr.span);
                   self.acc(cap.ln, var, ACC_READ | ACC_USE);
                   cap.ln
               })
@@ -980,7 +974,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             //
             let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
             let then_ln = self.propagate_through_expr(&then, succ);
-            let ln = self.live_node(expr.id, expr.span);
+            let ln = self.live_node(expr.hir_id, expr.span);
             self.init_from_succ(ln, else_ln);
             self.merge_from_succ(ln, then_ln, false);
             self.propagate_through_expr(&cond, ln)
@@ -1011,7 +1005,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             //   (  succ  )
             //
             //
-            let ln = self.live_node(expr.id, expr.span);
+            let ln = self.live_node(expr.hir_id, expr.span);
             self.init_empty(ln, succ);
             let mut first_merge = true;
             for arm in arms {
@@ -1132,7 +1126,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
             let r_succ = self.propagate_through_expr(&r, succ);
 
-            let ln = self.live_node(expr.id, expr.span);
+            let ln = self.live_node(expr.hir_id, expr.span);
             self.init_from_succ(ln, succ);
             self.merge_from_succ(ln, r_succ, false);
 
@@ -1249,7 +1243,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                     -> LiveNode {
         match expr.node {
           hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-              self.access_path(expr.id, path, succ, acc)
+              self.access_path(expr.hir_id, path, succ, acc)
           }
 
           // We do not track other places, so just propagate through
@@ -1260,22 +1254,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn access_var(&mut self, id: NodeId, nid: NodeId, succ: LiveNode, acc: u32, span: Span)
+    fn access_var(&mut self, hir_id: HirId, nid: NodeId, succ: LiveNode, acc: u32, span: Span)
                   -> LiveNode {
-        let ln = self.live_node(id, span);
+        let ln = self.live_node(hir_id, span);
         if acc != 0 {
             self.init_from_succ(ln, succ);
-            let var = self.variable(nid, span);
+            let var_hid = self.ir.tcx.hir.node_to_hir_id(nid);
+            let var = self.variable(var_hid, span);
             self.acc(ln, var, acc);
         }
         ln
     }
 
-    fn access_path(&mut self, id: NodeId, path: &hir::Path, succ: LiveNode, acc: u32)
+    fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32)
                    -> LiveNode {
         match path.def {
           Def::Local(nid) => {
-            self.access_var(id, nid, succ, acc, path.span)
+            self.access_var(hir_id, nid, succ, acc, path.span)
           }
           _ => succ
         }
@@ -1309,7 +1304,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
         // first iteration:
         let mut first_merge = true;
-        let ln = self.live_node(expr.id, expr.span);
+        let ln = self.live_node(expr.hir_id, expr.span);
         self.init_empty(ln, succ);
         match kind {
             LoopLoop => {}
@@ -1455,9 +1450,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                     // if there is no later assignment. If this local is actually
                     // mutable, then check for a reassignment to flag the mutability
                     // as being used.
-                    let ln = self.live_node(expr.id, expr.span);
-                    let var = self.variable(nid, expr.span);
-                    self.warn_about_dead_assign(expr.span, expr.id, ln, var);
+                    let ln = self.live_node(expr.hir_id, expr.span);
+                    let var_hid = self.ir.tcx.hir.node_to_hir_id(nid);
+                    let var = self.variable(var_hid, expr.span);
+                    self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var);
                 }
             }
             _ => {
@@ -1479,15 +1475,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
         for arg in &body.arguments {
-            arg.pat.each_binding(|_bm, p_id, _, path1| {
+            arg.pat.each_binding(|_bm, hir_id, _, path1| {
                 let sp = path1.span;
-                let var = self.variable(p_id, sp);
+                let var = self.variable(hir_id, sp);
                 // Ignore unused self.
                 let name = path1.node;
                 if name != keywords::SelfValue.name() {
-                    if !self.warn_about_unused(sp, p_id, entry_ln, var) {
+                    if !self.warn_about_unused(sp, hir_id, entry_ln, var) {
                         if self.live_on_entry(entry_ln, var).is_none() {
-                            self.report_dead_assign(p_id, sp, var, true);
+                            self.report_dead_assign(hir_id, sp, var, true);
                         }
                     }
                 }
@@ -1505,7 +1501,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn warn_about_unused(&self,
                          sp: Span,
-                         id: NodeId,
+                         hir_id: HirId,
                          ln: LiveNode,
                          var: Variable)
                          -> bool {
@@ -1527,14 +1523,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
                 if is_assigned {
                     self.ir.tcx
-                        .lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
-                                        &format!("variable `{}` is assigned to, but never used",
-                                                 name),
-                                        &suggest_underscore_msg);
+                        .lint_hir_note(lint::builtin::UNUSED_VARIABLES, hir_id, sp,
+                                       &format!("variable `{}` is assigned to, but never used",
+                                                name),
+                                       &suggest_underscore_msg);
                 } else if name != "self" {
                     let msg = format!("unused variable: `{}`", name);
                     let mut err = self.ir.tcx
-                        .struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg);
+                        .struct_span_lint_hir(lint::builtin::UNUSED_VARIABLES, hir_id, sp, &msg);
                     if self.ir.variable_is_shorthand(var) {
                         err.span_suggestion_with_applicability(sp, "try ignoring the field",
                                                                format!("{}: _", name),
@@ -1557,21 +1553,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn warn_about_dead_assign(&self,
                               sp: Span,
-                              id: NodeId,
+                              hir_id: HirId,
                               ln: LiveNode,
                               var: Variable) {
         if self.live_on_exit(ln, var).is_none() {
-            self.report_dead_assign(id, sp, var, false);
+            self.report_dead_assign(hir_id, sp, var, false);
         }
     }
 
-    fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) {
+    fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) {
         if let Some(name) = self.should_warn(var) {
             if is_argument {
-                self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
+                self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
                     &format!("value passed to `{}` is never read", name));
             } else {
-                self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp,
+                self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp,
                     &format!("value assigned to `{}` is never read", name));
             }
         }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 39c4da08b03a3..37732708733b0 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             // FIXME
             None if self.is_tainted_by_errors() => Err(()),
             None => {
-                let id = self.tcx.hir.definitions().find_node_for_hir_id(id);
+                let id = self.tcx.hir.hir_to_node_id(id);
                 bug!("no type for node {}: {} in mem_categorization",
                      id, self.tcx.hir.node_to_string(id));
             }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2b2da6f842bb6..9d3dda46dade1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -266,9 +266,7 @@ fn validate_hir_id_for_typeck_tables(local_id_root: Option<DefId>,
         if let Some(local_id_root) = local_id_root {
             if hir_id.owner != local_id_root.index {
                 ty::tls::with(|tcx| {
-                    let node_id = tcx.hir
-                                     .definitions()
-                                     .find_node_for_hir_id(hir_id);
+                    let node_id = tcx.hir.hir_to_node_id(hir_id);
 
                     bug!("node {} with HirId::owner {:?} cannot be placed in \
                           TypeckTables with local_id_root {:?}",
@@ -527,7 +525,7 @@ impl<'tcx> TypeckTables<'tcx> {
             None => {
                 bug!("node_id_to_type: no type for node `{}`",
                     tls::with(|tcx| {
-                        let id = tcx.hir.definitions().find_node_for_hir_id(id);
+                        let id = tcx.hir.hir_to_node_id(id);
                         tcx.hir.node_to_string(id)
                     }))
             }
@@ -2544,6 +2542,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         &self.intern_goals(&[goal])[0]
     }
 
+    pub fn lint_hir<S: Into<MultiSpan>>(self,
+                                        lint: &'static Lint,
+                                        hir_id: HirId,
+                                        span: S,
+                                        msg: &str) {
+        self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
+    }
+
     pub fn lint_node<S: Into<MultiSpan>>(self,
                                          lint: &'static Lint,
                                          id: NodeId,
@@ -2552,6 +2558,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.struct_span_lint_node(lint, id, span.into(), msg).emit()
     }
 
+    pub fn lint_hir_note<S: Into<MultiSpan>>(self,
+                                              lint: &'static Lint,
+                                              hir_id: HirId,
+                                              span: S,
+                                              msg: &str,
+                                              note: &str) {
+        let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg);
+        err.note(note);
+        err.emit()
+    }
+
     pub fn lint_node_note<S: Into<MultiSpan>>(self,
                                               lint: &'static Lint,
                                               id: NodeId,
@@ -2590,6 +2607,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
+    pub fn struct_span_lint_hir<S: Into<MultiSpan>>(self,
+                                                    lint: &'static Lint,
+                                                    hir_id: HirId,
+                                                    span: S,
+                                                    msg: &str)
+        -> DiagnosticBuilder<'tcx>
+    {
+        let node_id = self.hir.hir_to_node_id(hir_id);
+        let (level, src) = self.lint_level_at_node(lint, node_id);
+        lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
+    }
+
     pub fn struct_span_lint_node<S: Into<MultiSpan>>(self,
                                                      lint: &'static Lint,
                                                      id: NodeId,
diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs
index f98a8f834df8a..0dc71af9db694 100644
--- a/src/librustc/util/nodemap.rs
+++ b/src/librustc/util/nodemap.rs
@@ -19,20 +19,16 @@ use syntax::ast;
 pub use rustc_data_structures::fx::FxHashMap;
 pub use rustc_data_structures::fx::FxHashSet;
 
-pub type NodeMap<T> = FxHashMap<ast::NodeId, T>;
-pub type DefIdMap<T> = FxHashMap<DefId, T>;
-pub type HirIdMap<T> = FxHashMap<HirId, T>;
-pub type ItemLocalMap<T> = FxHashMap<ItemLocalId, T>;
-
-pub type NodeSet = FxHashSet<ast::NodeId>;
-pub type DefIdSet = FxHashSet<DefId>;
-pub type HirIdSet = FxHashSet<HirId>;
-pub type ItemLocalSet = FxHashSet<ItemLocalId>;
-
-pub fn NodeMap<T>() -> NodeMap<T> { FxHashMap() }
-pub fn DefIdMap<T>() -> DefIdMap<T> { FxHashMap() }
-pub fn ItemLocalMap<T>() -> ItemLocalMap<T> { FxHashMap() }
-pub fn NodeSet() -> NodeSet { FxHashSet() }
-pub fn DefIdSet() -> DefIdSet { FxHashSet() }
-pub fn ItemLocalSet() -> ItemLocalSet { FxHashSet() }
-
+macro_rules! define_id_collections {
+    ($map_name:ident, $set_name:ident, $key:ty) => {
+        pub type $map_name<T> = FxHashMap<$key, T>;
+        pub fn $map_name<T>() -> $map_name<T> { FxHashMap() }
+        pub type $set_name = FxHashSet<$key>;
+        pub fn $set_name() -> $set_name { FxHashSet() }
+    }
+}
+
+define_id_collections!(NodeMap, NodeSet, ast::NodeId);
+define_id_collections!(DefIdMap, DefIdSet, DefId);
+define_id_collections!(HirIdMap, HirIdSet, HirId);
+define_id_collections!(ItemLocalMap, ItemLocalSet, ItemLocalId);
diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs
index 7bcd8a185453b..b2b4c7d777eab 100644
--- a/src/librustc_borrowck/borrowck/unused.rs
+++ b/src/librustc_borrowck/borrowck/unused.rs
@@ -46,17 +46,16 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
         let tcx = self.bccx.tcx;
         let mut mutables = FxHashMap();
         for p in pats {
-            p.each_binding(|_, id, span, path1| {
+            p.each_binding(|_, hir_id, span, path1| {
                 let name = path1.node;
 
                 // Skip anything that looks like `_foo`
                 if name.as_str().starts_with("_") {
-                    return
+                    return;
                 }
 
                 // Skip anything that looks like `&foo` or `&mut foo`, only look
                 // for by-value bindings
-                let hir_id = tcx.hir.node_to_hir_id(id);
                 let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) {
                     Some(&bm) => bm,
                     None => span_bug!(span, "missing binding mode"),
@@ -66,25 +65,26 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
                     _ => return,
                 }
 
-                mutables.entry(name).or_insert(Vec::new()).push((id, hir_id, span));
+                mutables.entry(name).or_insert(Vec::new()).push((hir_id, span));
             });
         }
 
         for (_name, ids) in mutables {
             // If any id for this name was used mutably then consider them all
             // ok, so move on to the next
-            if ids.iter().any(|&(_, ref id, _)| self.used_mut.contains(id)) {
-                continue
+            if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) {
+                continue;
             }
 
-            let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2);
+            let (hir_id, span) = ids[0];
+            let mut_span = tcx.sess.codemap().span_until_non_whitespace(span);
 
             // Ok, every name wasn't used mutably, so issue a warning that this
             // didn't need to be mutable.
-            tcx.struct_span_lint_node(UNUSED_MUT,
-                                      ids[0].0,
-                                      ids[0].2,
-                                      "variable does not need to be mutable")
+            tcx.struct_span_lint_hir(UNUSED_MUT,
+                                     hir_id,
+                                     span,
+                                     "variable does not need to be mutable")
                 .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
                 .emit();
         }
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 77bcd88cecb6e..7c44a8d4d5f3b 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -499,8 +499,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
                                    pats: &[P<Pat>]) {
     let mut by_ref_span = None;
     for pat in pats {
-        pat.each_binding(|_, id, span, _path| {
-            let hir_id = cx.tcx.hir.node_to_hir_id(id);
+        pat.each_binding(|_, hir_id, span, _path| {
             let bm = *cx.tables
                         .pat_binding_modes()
                         .get(hir_id)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9452d2332cf4a..90b974fb972c0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2110,7 +2110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Some(&t) => t,
             None if self.is_tainted_by_errors() => self.tcx.types.err,
             None => {
-                let node_id = self.tcx.hir.definitions().find_node_for_hir_id(id);
+                let node_id = self.tcx.hir.hir_to_node_id(id);
                 bug!("no type for node {}: {} in fcx {}",
                      node_id, self.tcx.hir.node_to_string(node_id),
                      self.tag());
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index badf5bcb6a9a0..fa8045d70321f 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
         debug!("regionck::visit_pat(pat={:?})", pat);
-        pat.each_binding(|_, id, span, _| {
+        pat.each_binding(|_, hir_id, span, _| {
             // If we have a variable that contains region'd data, that
             // data will be accessible from anywhere that the variable is
             // accessed. We must be wary of loops like this:
@@ -403,8 +403,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             // iteration. The easiest way to guarantee this is to require
             // that the lifetime of any regions that appear in a
             // variable's type enclose at least the variable's scope.
-
-            let hir_id = self.tcx.hir.node_to_hir_id(id);
             let var_scope = self.region_scope_tree.var_scope(hir_id.local_id);
             let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index b0ee1154e863b..f295d1763c4c7 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -560,7 +560,7 @@ impl Locatable for DefIndex {
 
 impl Locatable for hir::HirId {
     fn to_span(&self, tcx: &TyCtxt) -> Span {
-        let node_id = tcx.hir.definitions().find_node_for_hir_id(*self);
+        let node_id = tcx.hir.hir_to_node_id(*self);
         tcx.hir.span(node_id)
     }
 }
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index f2f1e2938cb12..bff849d7ae8e9 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -106,7 +106,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         }
         assert_eq!(def_id.krate, LOCAL_CRATE);
         let hir_id = tcx.hir.definitions().def_index_to_hir_id(def_id.index);
-        let id = tcx.hir.definitions().find_node_for_hir_id(hir_id);
+        let id = tcx.hir.hir_to_node_id(hir_id);
         let lint = lint::builtin::UNUSED_EXTERN_CRATES;
         let msg = "unused extern crate";
         tcx.lint_node(lint, id, span, msg);