use visitor for contains_self
This commit is contained in:
parent
12d1d6f9e8
commit
aea2eb7da7
1 changed files with 12 additions and 88 deletions
100
src/shadow.rs
100
src/shadow.rs
|
@ -2,7 +2,7 @@ use std::ops::Deref;
|
||||||
use rustc_front::hir::*;
|
use rustc_front::hir::*;
|
||||||
use reexport::*;
|
use reexport::*;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use rustc_front::visit::FnKind;
|
use rustc_front::visit::{Visitor, FnKind};
|
||||||
|
|
||||||
use rustc::lint::*;
|
use rustc::lint::*;
|
||||||
use rustc::middle::def::Def::{DefVariant, DefStruct};
|
use rustc::middle::def::Def::{DefVariant, DefStruct};
|
||||||
|
@ -269,97 +269,21 @@ fn path_eq_name(name: Name, path: &Path) -> bool {
|
||||||
path.segments[0].identifier.name == name
|
path.segments[0].identifier.name == name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_self(name: Name, expr: &Expr) -> bool {
|
struct ContainsSelf {
|
||||||
match expr.node {
|
name: Name,
|
||||||
// the "self" name itself (maybe)
|
result: bool
|
||||||
ExprPath(_, ref path) => path_eq_name(name, path),
|
|
||||||
// no subexprs
|
|
||||||
ExprLit(_) => false,
|
|
||||||
// one subexpr
|
|
||||||
ExprUnary(_, ref e) | ExprField(ref e, _) |
|
|
||||||
ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) |
|
|
||||||
ExprCast(ref e, _) =>
|
|
||||||
contains_self(name, e),
|
|
||||||
// two subexprs
|
|
||||||
ExprBinary(_, ref l, ref r) | ExprIndex(ref l, ref r) |
|
|
||||||
ExprAssign(ref l, ref r) | ExprAssignOp(_, ref l, ref r) |
|
|
||||||
ExprRepeat(ref l, ref r) =>
|
|
||||||
contains_self(name, l) || contains_self(name, r),
|
|
||||||
// one optional subexpr
|
|
||||||
ExprRet(ref oe) =>
|
|
||||||
oe.as_ref().map_or(false, |ref e| contains_self(name, e)),
|
|
||||||
// two optional subexprs
|
|
||||||
ExprRange(ref ol, ref or) =>
|
|
||||||
ol.as_ref().map_or(false, |ref e| contains_self(name, e)) ||
|
|
||||||
or.as_ref().map_or(false, |ref e| contains_self(name, e)),
|
|
||||||
// one subblock
|
|
||||||
ExprBlock(ref block) | ExprLoop(ref block, _) |
|
|
||||||
ExprClosure(_, _, ref block) =>
|
|
||||||
contains_block_self(name, block),
|
|
||||||
// one vec
|
|
||||||
ExprMethodCall(_, _, ref v) | ExprVec(ref v) | ExprTup(ref v) =>
|
|
||||||
v.iter().any(|ref a| contains_self(name, a)),
|
|
||||||
// one expr, one vec
|
|
||||||
ExprCall(ref fun, ref args) =>
|
|
||||||
contains_self(name, fun) ||
|
|
||||||
args.iter().any(|ref a| contains_self(name, a)),
|
|
||||||
// special ones
|
|
||||||
ExprIf(ref cond, ref then, ref otherwise) =>
|
|
||||||
contains_self(name, cond) || contains_block_self(name, then) ||
|
|
||||||
otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
|
|
||||||
ExprWhile(ref e, ref block, _) =>
|
|
||||||
contains_self(name, e) || contains_block_self(name, block),
|
|
||||||
ExprMatch(ref e, ref arms, _) =>
|
|
||||||
contains_self(name, e) ||
|
|
||||||
arms.iter().any(
|
|
||||||
|ref arm|
|
|
||||||
arm.pats.iter().any(|ref pat| contains_pat_self(name, pat)) ||
|
|
||||||
arm.guard.as_ref().map_or(false, |ref g| contains_self(name, g)) ||
|
|
||||||
contains_self(name, &arm.body)),
|
|
||||||
ExprStruct(_, ref fields, ref other) =>
|
|
||||||
fields.iter().any(|ref f| contains_self(name, &f.expr)) ||
|
|
||||||
other.as_ref().map_or(false, |ref e| contains_self(name, e)),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_block_self(name: Name, block: &Block) -> bool {
|
impl<'v> Visitor<'v> for ContainsSelf {
|
||||||
for stmt in &block.stmts {
|
fn visit_name(&mut self, _: Span, name: Name) {
|
||||||
match stmt.node {
|
if self.name == name {
|
||||||
StmtDecl(ref decl, _) =>
|
self.result = true;
|
||||||
if let DeclLocal(ref local) = decl.node {
|
|
||||||
//TODO: We don't currently handle the case where the name
|
|
||||||
//is shadowed wiithin the block; this means code including this
|
|
||||||
//degenerate pattern will get the wrong warning.
|
|
||||||
if let Some(ref init) = local.init {
|
|
||||||
if contains_self(name, init) { return true; }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
|
|
||||||
if contains_self(name, e) { return true }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_pat_self(name: Name, pat: &Pat) -> bool {
|
fn contains_self(name: Name, expr: &Expr) -> bool {
|
||||||
match pat.node {
|
let mut cs = ContainsSelf { name: name, result: false };
|
||||||
PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
|
cs.visit_expr(expr);
|
||||||
inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
|
cs.result
|
||||||
PatEnum(_, ref opats) => opats.as_ref().map_or(false,
|
|
||||||
|pats| pats.iter().any(|p| contains_pat_self(name, p))),
|
|
||||||
PatQPath(_, ref path) => path_eq_name(name, path),
|
|
||||||
PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
|
|
||||||
|ref fp| contains_pat_self(name, &fp.node.pat)),
|
|
||||||
PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
|
|
||||||
PatBox(ref p) |
|
|
||||||
PatRegion(ref p, _) => contains_pat_self(name, p),
|
|
||||||
PatRange(ref from, ref until) =>
|
|
||||||
contains_self(name, from) || contains_self(name, until),
|
|
||||||
PatVec(ref pre, ref opt, ref post) =>
|
|
||||||
pre.iter().any(|ref p| contains_pat_self(name, p)) ||
|
|
||||||
opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
|
|
||||||
post.iter().any(|ref p| contains_pat_self(name, p)),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue