diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 31e6f3907dcd..877bf6f52a4c 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -44,6 +44,7 @@ use syntax::attr::AttrMetaMethods; use syntax::attr; use syntax::codemap::Span; use syntax::visit::{Visitor, FnKind}; +use syntax::parse::token::InternedString; use syntax::{ast, ast_util, visit}; /// Information about the registered lints. @@ -193,6 +194,38 @@ macro_rules! run_lints ( ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.lints.passes = Some(passes); })) +/// Parse the lint attributes into a vector, with `Err`s for malformed lint +/// attributes. Writing this as an iterator is an enormous mess. +pub fn gather_attrs(attrs: &[ast::Attribute]) + -> Vec> { + let mut out = vec!(); + for attr in attrs.iter() { + let level = match Level::from_str(attr.name().get()) { + None => continue, + Some(lvl) => lvl, + }; + + attr::mark_used(attr); + + let meta = attr.node.value; + let metas = match meta.node { + ast::MetaList(_, ref metas) => metas, + _ => { + out.push(Err(meta.span)); + continue; + } + }; + + for meta in metas.iter() { + out.push(match meta.node { + ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), + _ => Err(meta.span), + }); + } + } + out +} + /// Emit a lint as a warning or an error (or not at all) /// according to `level`. /// @@ -295,9 +328,27 @@ impl<'a> Context<'a> { // current dictionary of lint information. Along the way, keep a history // of what we changed so we can roll everything back after invoking the // specified closure - let lint_attrs = self.gather_lint_attrs(attrs); let mut pushed = 0u; - for (lint_id, level, span) in lint_attrs.move_iter() { + + for result in gather_attrs(attrs).move_iter() { + let (lint_id, level, span) = match result { + Err(span) => { + self.tcx.sess.span_err(span, "malformed lint attribute"); + continue; + } + Ok((lint_name, level, span)) => { + match self.lints.by_name.find_equiv(&lint_name.get()) { + Some(&lint_id) => (lint_id, level, span), + None => { + self.span_lint(builtin::UNRECOGNIZED_LINT, span, + format!("unknown `{}` attribute: `{}`", + level.as_str(), lint_name).as_slice()); + continue; + } + } + } + }; + let now = self.lints.get_level_source(lint_id).val0(); if now == Forbid && level != Forbid { let lint_name = lint_id.as_str(); @@ -331,46 +382,6 @@ impl<'a> Context<'a> { }; f(&mut v); } - - fn gather_lint_attrs(&mut self, attrs: &[ast::Attribute]) -> Vec<(LintId, Level, Span)> { - // Doing this as an iterator is messy due to multiple borrowing. - // Allocating and copying these should be quick. - let mut out = vec!(); - for attr in attrs.iter() { - let level = match Level::from_str(attr.name().get()) { - None => continue, - Some(lvl) => lvl, - }; - - attr::mark_used(attr); - - let meta = attr.node.value; - let metas = match meta.node { - ast::MetaList(_, ref metas) => metas, - _ => { - self.tcx.sess.span_err(meta.span, "malformed lint attribute"); - continue; - } - }; - - for meta in metas.iter() { - match meta.node { - ast::MetaWord(ref lint_name) => { - match self.lints.by_name.find_equiv(&lint_name.get()) { - Some(lint_id) => out.push((*lint_id, level, meta.span)), - - None => self.span_lint(builtin::UNRECOGNIZED_LINT, - meta.span, - format!("unknown `{}` attribute: `{}`", - level.as_str(), lint_name).as_slice()), - } - } - _ => self.tcx.sess.span_err(meta.span, "malformed lint attribute"), - } - } - } - out - } } impl<'a> AstConv for Context<'a>{ diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 598c5dd3002f..33facce29977 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -36,7 +36,7 @@ use syntax::codemap::Span; use syntax::visit::FnKind; use syntax::ast; -pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate}; +pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs}; /// Specification of a single lint. pub struct Lint { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 50ba073aafc2..156b88400677 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -269,16 +269,11 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { return true; } - // FIXME: use the lint attr parsing already in rustc::lint - for attr in attrs.iter().filter(|a| a.check_name("allow")) { - match attr.node.value.node { - ast::MetaList(_, ref metas) => for meta in metas.iter() { - match meta.node { - ast::MetaWord(ref name) if name.get() == "dead_code" - => return true, - _ => (), - } - }, + let dead_code = lint::builtin::DEAD_CODE.name_lower(); + for attr in lint::gather_attrs(attrs).move_iter() { + match attr { + Ok((ref name, lint::Allow, _)) + if name.get() == dead_code.as_slice() => return true, _ => (), } }