Skip to content

Commit 37f2f71

Browse files
committed
rustc: Add lint for unknown attributes
1 parent 365c44c commit 37f2f71

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

src/librustc/middle/lint.rs

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -798,36 +798,65 @@ fn check_heap_item(cx: &Context, it: &ast::item) {
798798
}
799799
}
800800

801-
// check if crate-level attribute is used on item,
802-
// since it is usually caused by mistake of semicolon omission.
803-
// also make error on obsolete attributes for less confusion.
804-
fn check_item_attribute_usage(cx: &Context, it: &ast::item) {
805-
let crate_attrs = ["crate_type", "link", "feature", "no_uv", "no_main", "no_std"];
801+
fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
802+
// check if element has crate-level, obsolete, or any unknown attributes.
803+
804+
let crate_attrs = [
805+
"crate_type", "link", "feature", "no_uv", "no_main", "no_std",
806+
"comment", "license", "copyright", // not used in rustc now
807+
];
808+
806809
let obsolete_attrs = [
807810
("abi", "extern \"abi\" fn"),
808811
("auto_encode", "#[deriving(Encodable)]"),
809812
("auto_decode", "#[deriving(Decodable)]"),
810813
];
811814

812-
for attr in it.attrs.iter() {
815+
let other_attrs = [
816+
// item-level
817+
"address_insignificant", // can be crate-level too
818+
"allow", "deny", "forbid", "warn", // lint options
819+
"deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability
820+
"crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze",
821+
"no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag",
822+
"packed", "simd", "repr", "deriving", "unsafe_destructor",
823+
824+
// mod-level
825+
"path", "link_name", "link_args", "nolink", "macro_escape", "no_implicit_prelude",
826+
827+
// fn-level
828+
"test", "bench", "should_fail", "ignore", "inline", "lang", "main", "start",
829+
"fixed_stack_segment", "no_split_stack", "rust_stack", "cold",
830+
831+
// internal attribute: bypass privacy inside items
832+
"!resolve_unexported",
833+
];
834+
835+
for attr in attrs.iter() {
813836
let name = attr.node.value.name();
814837
for crate_attr in crate_attrs.iter() {
815838
if name.equiv(crate_attr) {
816839
let msg = match attr.node.style {
817-
ast::AttrOuter => "crate-level attribute should be an inner attribute: \
818-
add semicolon at end",
840+
ast::AttrOuter => "crate-level attribute should be an inner attribute: \
841+
add semicolon at end",
819842
ast::AttrInner => "crate-level attribute should be in the root module",
820843
};
821844
cx.span_lint(attribute_usage, attr.span, msg);
845+
return;
822846
}
823847
}
824848

825849
for &(obs_attr, obs_alter) in obsolete_attrs.iter() {
826850
if name.equiv(&obs_attr) {
827851
cx.span_lint(attribute_usage, attr.span,
828852
format!("obsolete attribute: use `{:s}` instead", obs_alter));
853+
return;
829854
}
830855
}
856+
857+
if !other_attrs.iter().any(|other_attr| { name.equiv(other_attr) }) {
858+
cx.span_lint(attribute_usage, attr.span, "unknown attribute");
859+
}
831860
}
832861
}
833862

@@ -1151,7 +1180,7 @@ impl<'self> Visitor<()> for Context<'self> {
11511180
check_item_non_uppercase_statics(cx, it);
11521181
check_heap_item(cx, it);
11531182
check_missing_doc_item(cx, it);
1154-
check_item_attribute_usage(cx, it);
1183+
check_attrs_usage(cx, it.attrs);
11551184

11561185
do cx.visit_ids |v| {
11571186
v.visit_item(it, ());
@@ -1161,6 +1190,20 @@ impl<'self> Visitor<()> for Context<'self> {
11611190
}
11621191
}
11631192

1193+
fn visit_foreign_item(&mut self, it: @ast::foreign_item, _: ()) {
1194+
do self.with_lint_attrs(it.attrs) |cx| {
1195+
check_attrs_usage(cx, it.attrs);
1196+
visit::walk_foreign_item(cx, it, ());
1197+
}
1198+
}
1199+
1200+
fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
1201+
do self.with_lint_attrs(i.attrs) |cx| {
1202+
check_attrs_usage(cx, i.attrs);
1203+
visit::walk_view_item(cx, i, ());
1204+
}
1205+
}
1206+
11641207
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
11651208
check_pat_non_uppercase_statics(self, p);
11661209
check_unused_mut_pat(self, p);
@@ -1210,6 +1253,7 @@ impl<'self> Visitor<()> for Context<'self> {
12101253
visit::fk_method(_, _, m) => {
12111254
do self.with_lint_attrs(m.attrs) |cx| {
12121255
check_missing_doc_method(cx, m);
1256+
check_attrs_usage(cx, m.attrs);
12131257

12141258
do cx.visit_ids |v| {
12151259
v.visit_fn(fk, decl, body, span, id, ());
@@ -1221,9 +1265,11 @@ impl<'self> Visitor<()> for Context<'self> {
12211265
}
12221266
}
12231267

1268+
12241269
fn visit_ty_method(&mut self, t: &ast::TypeMethod, _: ()) {
12251270
do self.with_lint_attrs(t.attrs) |cx| {
12261271
check_missing_doc_ty_method(cx, t);
1272+
check_attrs_usage(cx, t.attrs);
12271273

12281274
visit::walk_ty_method(cx, t, ());
12291275
}
@@ -1244,6 +1290,7 @@ impl<'self> Visitor<()> for Context<'self> {
12441290
fn visit_struct_field(&mut self, s: @ast::struct_field, _: ()) {
12451291
do self.with_lint_attrs(s.node.attrs) |cx| {
12461292
check_missing_doc_struct_field(cx, s);
1293+
check_attrs_usage(cx, s.node.attrs);
12471294

12481295
visit::walk_struct_field(cx, s, ());
12491296
}
@@ -1252,6 +1299,7 @@ impl<'self> Visitor<()> for Context<'self> {
12521299
fn visit_variant(&mut self, v: &ast::variant, g: &ast::Generics, _: ()) {
12531300
do self.with_lint_attrs(v.node.attrs) |cx| {
12541301
check_missing_doc_variant(cx, v);
1302+
check_attrs_usage(cx, v.node.attrs);
12551303

12561304
visit::walk_variant(cx, v, g, ());
12571305
}

0 commit comments

Comments
 (0)