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};
use syntax::symbol::keywords;
use syntax_pos::Span;
-use hir::Expr;
+use hir::{Expr, HirId};
use hir;
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
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
}
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>,
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(),
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 {
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);
}
}
}
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));
})
};
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() {
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);
}
}
}
}
}
- 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)
}));
});
}
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
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 });
}
}
});
// 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);
}
}
}
- 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
// 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);
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, _) => {
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;
};
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
})
//
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)
// ( 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 {
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);
-> 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
}
}
- 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
}
// 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 => {}
// 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);
}
}
_ => {
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);
}
}
}
fn warn_about_unused(&self,
sp: Span,
- id: NodeId,
+ hir_id: HirId,
ln: LiveNode,
var: Variable)
-> bool {
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),
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));
}
}