Created
November 9, 2014 00:49
-
-
Save mrhota/e4170b3148a589801d72 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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