First sketch of lint pass
Enough attributes are marked to cleanly compile an empty library.
This commit is contained in:
parent
c305473d3c
commit
50181add04
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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()
|
||||
|
@ -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")
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user