rustc: Add lint for unknown attributes
This commit is contained in:
parent
365c44cb2d
commit
37f2f7173b
@ -798,27 +798,51 @@ fn check_heap_item(cx: &Context, it: &ast::item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if crate-level attribute is used on item,
|
fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
|
||||||
// since it is usually caused by mistake of semicolon omission.
|
// check if element has crate-level, obsolete, or any unknown attributes.
|
||||||
// also make error on obsolete attributes for less confusion.
|
|
||||||
fn check_item_attribute_usage(cx: &Context, it: &ast::item) {
|
let crate_attrs = [
|
||||||
let crate_attrs = ["crate_type", "link", "feature", "no_uv", "no_main", "no_std"];
|
"crate_type", "link", "feature", "no_uv", "no_main", "no_std",
|
||||||
|
"comment", "license", "copyright", // not used in rustc now
|
||||||
|
];
|
||||||
|
|
||||||
let obsolete_attrs = [
|
let obsolete_attrs = [
|
||||||
("abi", "extern \"abi\" fn"),
|
("abi", "extern \"abi\" fn"),
|
||||||
("auto_encode", "#[deriving(Encodable)]"),
|
("auto_encode", "#[deriving(Encodable)]"),
|
||||||
("auto_decode", "#[deriving(Decodable)]"),
|
("auto_decode", "#[deriving(Decodable)]"),
|
||||||
];
|
];
|
||||||
|
|
||||||
for attr in it.attrs.iter() {
|
let other_attrs = [
|
||||||
|
// item-level
|
||||||
|
"address_insignificant", // can be crate-level too
|
||||||
|
"allow", "deny", "forbid", "warn", // lint options
|
||||||
|
"deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability
|
||||||
|
"crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze",
|
||||||
|
"no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag",
|
||||||
|
"packed", "simd", "repr", "deriving", "unsafe_destructor",
|
||||||
|
|
||||||
|
// mod-level
|
||||||
|
"path", "link_name", "link_args", "nolink", "macro_escape", "no_implicit_prelude",
|
||||||
|
|
||||||
|
// fn-level
|
||||||
|
"test", "bench", "should_fail", "ignore", "inline", "lang", "main", "start",
|
||||||
|
"fixed_stack_segment", "no_split_stack", "rust_stack", "cold",
|
||||||
|
|
||||||
|
// internal attribute: bypass privacy inside items
|
||||||
|
"!resolve_unexported",
|
||||||
|
];
|
||||||
|
|
||||||
|
for attr in attrs.iter() {
|
||||||
let name = attr.node.value.name();
|
let name = attr.node.value.name();
|
||||||
for crate_attr in crate_attrs.iter() {
|
for crate_attr in crate_attrs.iter() {
|
||||||
if name.equiv(crate_attr) {
|
if name.equiv(crate_attr) {
|
||||||
let msg = match attr.node.style {
|
let msg = match attr.node.style {
|
||||||
ast::AttrOuter => "crate-level attribute should be an inner attribute: \
|
ast::AttrOuter => "crate-level attribute should be an inner attribute: \
|
||||||
add semicolon at end",
|
add semicolon at end",
|
||||||
ast::AttrInner => "crate-level attribute should be in the root module",
|
ast::AttrInner => "crate-level attribute should be in the root module",
|
||||||
};
|
};
|
||||||
cx.span_lint(attribute_usage, attr.span, msg);
|
cx.span_lint(attribute_usage, attr.span, msg);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -826,8 +850,13 @@ fn check_item_attribute_usage(cx: &Context, it: &ast::item) {
|
|||||||
if name.equiv(&obs_attr) {
|
if name.equiv(&obs_attr) {
|
||||||
cx.span_lint(attribute_usage, attr.span,
|
cx.span_lint(attribute_usage, attr.span,
|
||||||
format!("obsolete attribute: use `{:s}` instead", obs_alter));
|
format!("obsolete attribute: use `{:s}` instead", obs_alter));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !other_attrs.iter().any(|other_attr| { name.equiv(other_attr) }) {
|
||||||
|
cx.span_lint(attribute_usage, attr.span, "unknown attribute");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,7 +1180,7 @@ impl<'self> Visitor<()> for Context<'self> {
|
|||||||
check_item_non_uppercase_statics(cx, it);
|
check_item_non_uppercase_statics(cx, it);
|
||||||
check_heap_item(cx, it);
|
check_heap_item(cx, it);
|
||||||
check_missing_doc_item(cx, it);
|
check_missing_doc_item(cx, it);
|
||||||
check_item_attribute_usage(cx, it);
|
check_attrs_usage(cx, it.attrs);
|
||||||
|
|
||||||
do cx.visit_ids |v| {
|
do cx.visit_ids |v| {
|
||||||
v.visit_item(it, ());
|
v.visit_item(it, ());
|
||||||
@ -1161,6 +1190,20 @@ impl<'self> Visitor<()> for Context<'self> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_foreign_item(&mut self, it: @ast::foreign_item, _: ()) {
|
||||||
|
do self.with_lint_attrs(it.attrs) |cx| {
|
||||||
|
check_attrs_usage(cx, it.attrs);
|
||||||
|
visit::walk_foreign_item(cx, it, ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
|
||||||
|
do self.with_lint_attrs(i.attrs) |cx| {
|
||||||
|
check_attrs_usage(cx, i.attrs);
|
||||||
|
visit::walk_view_item(cx, i, ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
|
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
|
||||||
check_pat_non_uppercase_statics(self, p);
|
check_pat_non_uppercase_statics(self, p);
|
||||||
check_unused_mut_pat(self, p);
|
check_unused_mut_pat(self, p);
|
||||||
@ -1210,6 +1253,7 @@ impl<'self> Visitor<()> for Context<'self> {
|
|||||||
visit::fk_method(_, _, m) => {
|
visit::fk_method(_, _, m) => {
|
||||||
do self.with_lint_attrs(m.attrs) |cx| {
|
do self.with_lint_attrs(m.attrs) |cx| {
|
||||||
check_missing_doc_method(cx, m);
|
check_missing_doc_method(cx, m);
|
||||||
|
check_attrs_usage(cx, m.attrs);
|
||||||
|
|
||||||
do cx.visit_ids |v| {
|
do cx.visit_ids |v| {
|
||||||
v.visit_fn(fk, decl, body, span, id, ());
|
v.visit_fn(fk, decl, body, span, id, ());
|
||||||
@ -1221,9 +1265,11 @@ impl<'self> Visitor<()> for Context<'self> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn visit_ty_method(&mut self, t: &ast::TypeMethod, _: ()) {
|
fn visit_ty_method(&mut self, t: &ast::TypeMethod, _: ()) {
|
||||||
do self.with_lint_attrs(t.attrs) |cx| {
|
do self.with_lint_attrs(t.attrs) |cx| {
|
||||||
check_missing_doc_ty_method(cx, t);
|
check_missing_doc_ty_method(cx, t);
|
||||||
|
check_attrs_usage(cx, t.attrs);
|
||||||
|
|
||||||
visit::walk_ty_method(cx, t, ());
|
visit::walk_ty_method(cx, t, ());
|
||||||
}
|
}
|
||||||
@ -1244,6 +1290,7 @@ impl<'self> Visitor<()> for Context<'self> {
|
|||||||
fn visit_struct_field(&mut self, s: @ast::struct_field, _: ()) {
|
fn visit_struct_field(&mut self, s: @ast::struct_field, _: ()) {
|
||||||
do self.with_lint_attrs(s.node.attrs) |cx| {
|
do self.with_lint_attrs(s.node.attrs) |cx| {
|
||||||
check_missing_doc_struct_field(cx, s);
|
check_missing_doc_struct_field(cx, s);
|
||||||
|
check_attrs_usage(cx, s.node.attrs);
|
||||||
|
|
||||||
visit::walk_struct_field(cx, s, ());
|
visit::walk_struct_field(cx, s, ());
|
||||||
}
|
}
|
||||||
@ -1252,6 +1299,7 @@ impl<'self> Visitor<()> for Context<'self> {
|
|||||||
fn visit_variant(&mut self, v: &ast::variant, g: &ast::Generics, _: ()) {
|
fn visit_variant(&mut self, v: &ast::variant, g: &ast::Generics, _: ()) {
|
||||||
do self.with_lint_attrs(v.node.attrs) |cx| {
|
do self.with_lint_attrs(v.node.attrs) |cx| {
|
||||||
check_missing_doc_variant(cx, v);
|
check_missing_doc_variant(cx, v);
|
||||||
|
check_attrs_usage(cx, v.node.attrs);
|
||||||
|
|
||||||
visit::walk_variant(cx, v, g, ());
|
visit::walk_variant(cx, v, g, ());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user