Skip to content

Instantly share code, notes, and snippets.

@mrhota
Created November 9, 2014 00:49
Show Gist options
  • Save mrhota/e4170b3148a589801d72 to your computer and use it in GitHub Desktop.
Save mrhota/e4170b3148a589801d72 to your computer and use it in GitHub Desktop.
#![forbid(shadowed_name)]
#![allow(unused_variables)]
pub fn main() {
let foo = 0i;
{
let foo = Some(2.0f64); //~ ERROR foo is shadowed
}
}
// ------------------------------------------
declare_lint!(pub SHADOWED_NAME, Allow,
"detects declarations which shadow names from enclosing scopes")
struct ShadowedNameVisitor<'a, 'tcx: 'a> {
cx: &'a Context<'a, 'tcx>,
shadowed_names: HashMap<ast::Name, ast::NodeId>,
}
// visits the whole crate, looking for shadowed names in Pat nodes
impl<'a, 'tcx, 'v> Visitor<'v> for ShadowedNameVisitor<'a, 'tcx> {
fn visit_pat(&mut self, p: &ast::Pat) {
match p.node {
ast::PatIdent(_, spannedident, _) => {
let name = spannedident.node.name;
match self.shadowed_names.entry(name) {
Vacant(entry) => {
entry.set(p.id);
},
Occupied(entry) => {
// name is potentially shadowing something!
let ref rmap = self.cx.tcx.region_maps;
let ref cx = self.cx;
let &origid = entry.get();
let origscope = match rmap.opt_encl_scope(origid) {
Some(s) => s,
None => return
};
let thisscope = match rmap.opt_encl_scope(p.id) {
Some(s) => s,
None => return
};
if origscope != thisscope {
let lvl = cx.current_level(SHADOWED_NAME);
if rmap.is_subscope_of(thisscope, origscope) {
cx.span_lint(SHADOWED_NAME, cx.tcx.map.span(origid),
format!("{} is shadowed",
token::get_name(name)).as_slice());
if lvl > lint::Allow {
span_note!(cx.sess(), p.span, "{} shadowed here",
token::get_name(name));
}
} else {
cx.span_lint(SHADOWED_NAME, p.span,
format!("{} is shadowed",
token::get_name(name)).as_slice());
if lvl > lint::Allow {
span_note!(cx.sess(), cx.tcx.map.span(origid),
"{} shadowed here",
token::get_name(name));
}
}
} else {
println!("{} scope was weird", name);
println!("origscope: {}", origscope);
println!("thisscope: {}", thisscope);
}
},
}
},
_ => {},
}
visit::walk_pat(self, p);
}
}
pub struct ShadowedName;
impl LintPass for ShadowedName {
fn get_lints(&self) -> LintArray {
lint_array!(SHADOWED_NAME)
}
fn check_crate(&mut self, cx: &Context, krate: &ast::Crate) {
let mut vis = ShadowedNameVisitor {
cx: cx,
shadowed_names: HashMap::new()
};
visit::walk_crate(&mut vis, krate);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment