Skip to content

Commit 50181ad

Browse files
committed
First sketch of lint pass
Enough attributes are marked to cleanly compile an empty library.
1 parent c305473 commit 50181ad

File tree

5 files changed

+39
-6
lines changed

5 files changed

+39
-6
lines changed

src/librustc/front/feature_gate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
327327
};
328328

329329
for attr in krate.attrs.iter() {
330-
if !attr.name().equiv(&("feature")) {
330+
if !attr.check_name("feature") {
331331
continue
332332
}
333333

src/librustc/front/std_inject.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
115115
InternedString::new("feature"),
116116
vec![attr::mk_word_item(InternedString::new("phase"))],
117117
));
118+
// std_inject runs after feature checking so manually mark this attr
119+
attr::mark_used(&feat_phase_attr);
118120
krate.attrs.push(feat_phase_attr);
119121

120122
krate
@@ -141,6 +143,8 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
141143

142144
let no_std_attr = attr::mk_attr_inner(attr::mk_attr_id(),
143145
attr::mk_word_item(InternedString::new("no_std")));
146+
// std_inject runs after feature checking so manually mark this attr
147+
attr::mark_used(&no_std_attr);
144148
krate.attrs.push(no_std_attr);
145149

146150
if !no_prelude(krate.attrs.as_slice()) {
@@ -154,6 +158,8 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
154158
vec!(
155159
attr::mk_word_item(InternedString::new("globs")),
156160
)));
161+
// std_inject runs after feature checking so manually mark this attr
162+
attr::mark_used(&globs_attr);
157163
krate.attrs.push(globs_attr);
158164

159165
krate.module = self.fold_mod(&krate.module);

src/librustc/middle/lint.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub enum Lint {
9090
UnusedUnsafe,
9191
UnsafeBlock,
9292
AttributeUsage,
93+
UnusedAttribute,
9394
UnknownFeatures,
9495
UnknownCrateType,
9596
UnsignedNegate,
@@ -288,6 +289,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
288289
default: Warn
289290
}),
290291

292+
("unused_attribute",
293+
LintSpec {
294+
lint: UnusedAttribute,
295+
desc: "detects attributes that were not used by the compiler",
296+
default: Allow
297+
}),
298+
291299
("unused_variable",
292300
LintSpec {
293301
lint: UnusedVariable,
@@ -619,7 +627,7 @@ pub fn each_lint(sess: &session::Session,
619627
let xs = [Allow, Warn, Deny, Forbid];
620628
for &level in xs.iter() {
621629
let level_name = level_to_str(level);
622-
for attr in attrs.iter().filter(|m| m.name().equiv(&level_name)) {
630+
for attr in attrs.iter().filter(|m| m.check_name(level_name)) {
623631
let meta = attr.node.value;
624632
let metas = match meta.node {
625633
ast::MetaList(_, ref metas) => metas,
@@ -1137,6 +1145,15 @@ fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
11371145
}
11381146
}
11391147

1148+
fn check_unused_attribute(cx: &Context, attrs: &[ast::Attribute]) {
1149+
for attr in attrs.iter() {
1150+
if !attr::is_used(attr) {
1151+
cx.span_lint(UnusedAttribute, attr.span,
1152+
format!("unused attribute {}", attr.name()).as_slice());
1153+
}
1154+
}
1155+
}
1156+
11401157
fn check_heap_expr(cx: &Context, e: &ast::Expr) {
11411158
let ty = ty::expr_ty(cx.tcx, e);
11421159
check_heap_type(cx, e.span, ty);
@@ -1694,6 +1711,7 @@ impl<'a> Visitor<()> for Context<'a> {
16941711
check_heap_item(cx, it);
16951712
check_missing_doc_item(cx, it);
16961713
check_attrs_usage(cx, it.attrs.as_slice());
1714+
check_unused_attribute(cx, it.attrs.as_slice());
16971715
check_raw_ptr_deriving(cx, it);
16981716

16991717
cx.visit_ids(|v| v.visit_item(it, ()));
@@ -1900,6 +1918,7 @@ pub fn check_crate(tcx: &ty::ctxt,
19001918
check_crate_attrs_usage(cx, krate.attrs.as_slice());
19011919
// since the root module isn't visited as an item (because it isn't an item), warn for it
19021920
// here.
1921+
check_unused_attribute(cx, krate.attrs.as_slice());
19031922
check_missing_doc_attrs(cx,
19041923
None,
19051924
krate.attrs.as_slice(),

src/libsyntax/attr.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ pub fn is_used(attr: &Attribute) -> bool {
3535
}
3636

3737
pub trait AttrMetaMethods {
38-
// This could be changed to `fn check_name(&self, name: InternedString) ->
39-
// bool` which would facilitate a side table recording which
40-
// attributes/meta items are used/unused.
38+
fn check_name(&self, name: &str) -> bool {
39+
name == self.name().get()
40+
}
4141

4242
/// Retrieve the name of the meta item, e.g. foo in #[foo],
4343
/// #[foo="bar"] and #[foo(bar)]
@@ -59,6 +59,14 @@ pub trait AttrMetaMethods {
5959
}
6060

6161
impl AttrMetaMethods for Attribute {
62+
fn check_name(&self, name: &str) -> bool {
63+
if name == self.name().get() {
64+
mark_used(self);
65+
true
66+
} else {
67+
false
68+
}
69+
}
6270
fn name(&self) -> InternedString { self.meta().name() }
6371
fn value_str(&self) -> Option<InternedString> {
6472
self.meta().value_str()

src/libsyntax/ext/expand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ pub fn expand_view_item(vi: &ast::ViewItem,
474474
match vi.node {
475475
ast::ViewItemExternCrate(..) => {
476476
let should_load = vi.attrs.iter().any(|attr| {
477-
attr.name().get() == "phase" &&
477+
attr.check_name("phase") &&
478478
attr.meta_item_list().map_or(false, |phases| {
479479
attr::contains_name(phases, "syntax")
480480
})

0 commit comments

Comments
 (0)