about summary refs log tree commit diff
diff options
context:
space:
mode:
authorklutzy <klutzytheklutzy@gmail.com>2013-11-26 00:22:40 +0900
committerklutzy <klutzytheklutzy@gmail.com>2013-11-26 14:07:48 +0900
commitfa2077af990dbcd71c0e5682ae9207c71485d384 (patch)
treededcca6c9904bb735a53bc5ecb1eb2d5203ac7e6
parent9432e2a25dc5f3a71aa4f95a9dd6ba17198c79bd (diff)
downloadrust-fa2077af990dbcd71c0e5682ae9207c71485d384.tar.gz
rust-fa2077af990dbcd71c0e5682ae9207c71485d384.zip
rustc: Add crate-level attribute lint
-rw-r--r--src/librustc/middle/lint.rs83
-rw-r--r--src/test/compile-fail/lint-unknown-attr.rs2
2 files changed, 51 insertions, 34 deletions
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 42dbe3f6d9e..d67677f0783 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -798,43 +798,55 @@ fn check_heap_item(cx: &Context, it: &ast::item) {
     }
 }
 
+static crate_attrs: &'static [&'static str] = &[
+    "crate_type", "link", "feature", "no_uv", "no_main", "no_std",
+    "desc", "comment", "license", "copyright", // not used in rustc now
+];
+
+
+static obsolete_attrs: &'static [(&'static str, &'static str)] = &[
+    ("abi", "Use `extern \"abi\" fn` instead"),
+    ("auto_encode", "Use `#[deriving(Encodable)]` instead"),
+    ("auto_decode", "Use `#[deriving(Decodable)]` instead"),
+    ("fast_ffi", "Remove it"),
+    ("fixed_stack_segment", "Remove it"),
+    ("rust_stack", "Remove it"),
+];
+
+static other_attrs: &'static [&'static str] = &[
+    // 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",
+    "no_split_stack", "cold",
+
+    // internal attribute: bypass privacy inside items
+    "!resolve_unexported",
+];
+
+fn check_crate_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
+
+    for attr in attrs.iter() {
+        let name = attr.node.value.name();
+        let mut iter = crate_attrs.iter().chain(other_attrs.iter());
+        if !iter.any(|other_attr| { name.equiv(other_attr) }) {
+            cx.span_lint(attribute_usage, attr.span, "unknown crate attribute");
+        }
+    }
+}
+
 fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
     // check if element has crate-level, obsolete, or any unknown attributes.
 
-    let crate_attrs = [
-        "crate_type", "link", "feature", "no_uv", "no_main", "no_std",
-        "comment", "license", "copyright", // not used in rustc now
-    ];
-
-    let obsolete_attrs = [
-        ("abi", "Use `extern \"abi\" fn` instead"),
-        ("auto_encode", "Use `#[deriving(Encodable)]` instead"),
-        ("auto_decode", "Use `#[deriving(Decodable)]` instead"),
-        ("fast_ffi", "Remove it"),
-        ("fixed_stack_segment", "Remove it"),
-        ("rust_stack", "Remove it"),
-    ];
-
-    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",
-        "no_split_stack", "cold",
-
-        // internal attribute: bypass privacy inside items
-        "!resolve_unexported",
-    ];
-
     for attr in attrs.iter() {
         let name = attr.node.value.name();
         for crate_attr in crate_attrs.iter() {
@@ -1349,6 +1361,9 @@ pub fn check_crate(tcx: ty::ctxt,
             v.visited_outermost = true;
             visit::walk_crate(v, crate, ());
         }
+
+        check_crate_attrs_usage(cx, crate.attrs);
+
         visit::walk_crate(cx, crate, ());
     }
 
diff --git a/src/test/compile-fail/lint-unknown-attr.rs b/src/test/compile-fail/lint-unknown-attr.rs
index 2ec7706addf..ce83ba464c0 100644
--- a/src/test/compile-fail/lint-unknown-attr.rs
+++ b/src/test/compile-fail/lint-unknown-attr.rs
@@ -13,6 +13,8 @@
 
 #[deny(attribute_usage)];
 
+#[mutable_doc]; //~ ERROR: unknown crate attribute
+
 #[dance] mod a {} //~ ERROR: unknown attribute
 
 #[dance] fn main() {} //~ ERROR: unknown attribute