First sketch of lint pass

Enough attributes are marked to cleanly compile an empty library.
This commit is contained in:
Steven Fackler 2014-05-20 22:07:42 -07:00
parent c305473d3c
commit 50181add04
5 changed files with 39 additions and 6 deletions

View File

@ -327,7 +327,7 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
};
for attr in krate.attrs.iter() {
if !attr.name().equiv(&("feature")) {
if !attr.check_name("feature") {
continue
}

View File

@ -115,6 +115,8 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
InternedString::new("feature"),
vec![attr::mk_word_item(InternedString::new("phase"))],
));
// std_inject runs after feature checking so manually mark this attr
attr::mark_used(&feat_phase_attr);
krate.attrs.push(feat_phase_attr);
krate
@ -141,6 +143,8 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
let no_std_attr = attr::mk_attr_inner(attr::mk_attr_id(),
attr::mk_word_item(InternedString::new("no_std")));
// std_inject runs after feature checking so manually mark this attr
attr::mark_used(&no_std_attr);
krate.attrs.push(no_std_attr);
if !no_prelude(krate.attrs.as_slice()) {
@ -154,6 +158,8 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
vec!(
attr::mk_word_item(InternedString::new("globs")),
)));
// std_inject runs after feature checking so manually mark this attr
attr::mark_used(&globs_attr);
krate.attrs.push(globs_attr);
krate.module = self.fold_mod(&krate.module);

View File

@ -90,6 +90,7 @@ pub enum Lint {
UnusedUnsafe,
UnsafeBlock,
AttributeUsage,
UnusedAttribute,
UnknownFeatures,
UnknownCrateType,
UnsignedNegate,
@ -288,6 +289,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
default: Warn
}),
("unused_attribute",
LintSpec {
lint: UnusedAttribute,
desc: "detects attributes that were not used by the compiler",
default: Allow
}),
("unused_variable",
LintSpec {
lint: UnusedVariable,
@ -619,7 +627,7 @@ pub fn each_lint(sess: &session::Session,
let xs = [Allow, Warn, Deny, Forbid];
for &level in xs.iter() {
let level_name = level_to_str(level);
for attr in attrs.iter().filter(|m| m.name().equiv(&level_name)) {
for attr in attrs.iter().filter(|m| m.check_name(level_name)) {
let meta = attr.node.value;
let metas = match meta.node {
ast::MetaList(_, ref metas) => metas,
@ -1137,6 +1145,15 @@ fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
}
}
fn check_unused_attribute(cx: &Context, attrs: &[ast::Attribute]) {
for attr in attrs.iter() {
if !attr::is_used(attr) {
cx.span_lint(UnusedAttribute, attr.span,
format!("unused attribute {}", attr.name()).as_slice());
}
}
}
fn check_heap_expr(cx: &Context, e: &ast::Expr) {
let ty = ty::expr_ty(cx.tcx, e);
check_heap_type(cx, e.span, ty);
@ -1694,6 +1711,7 @@ impl<'a> Visitor<()> for Context<'a> {
check_heap_item(cx, it);
check_missing_doc_item(cx, it);
check_attrs_usage(cx, it.attrs.as_slice());
check_unused_attribute(cx, it.attrs.as_slice());
check_raw_ptr_deriving(cx, it);
cx.visit_ids(|v| v.visit_item(it, ()));
@ -1900,6 +1918,7 @@ pub fn check_crate(tcx: &ty::ctxt,
check_crate_attrs_usage(cx, krate.attrs.as_slice());
// since the root module isn't visited as an item (because it isn't an item), warn for it
// here.
check_unused_attribute(cx, krate.attrs.as_slice());
check_missing_doc_attrs(cx,
None,
krate.attrs.as_slice(),

View File

@ -35,9 +35,9 @@ pub fn is_used(attr: &Attribute) -> bool {
}
pub trait AttrMetaMethods {
// This could be changed to `fn check_name(&self, name: InternedString) ->
// bool` which would facilitate a side table recording which
// attributes/meta items are used/unused.
fn check_name(&self, name: &str) -> bool {
name == self.name().get()
}
/// Retrieve the name of the meta item, e.g. foo in #[foo],
/// #[foo="bar"] and #[foo(bar)]
@ -59,6 +59,14 @@ pub trait AttrMetaMethods {
}
impl AttrMetaMethods for Attribute {
fn check_name(&self, name: &str) -> bool {
if name == self.name().get() {
mark_used(self);
true
} else {
false
}
}
fn name(&self) -> InternedString { self.meta().name() }
fn value_str(&self) -> Option<InternedString> {
self.meta().value_str()

View File

@ -474,7 +474,7 @@ pub fn expand_view_item(vi: &ast::ViewItem,
match vi.node {
ast::ViewItemExternCrate(..) => {
let should_load = vi.attrs.iter().any(|attr| {
attr.name().get() == "phase" &&
attr.check_name("phase") &&
attr.meta_item_list().map_or(false, |phases| {
attr::contains_name(phases, "syntax")
})