Skip to content

Commit c6a87c2

Browse files
committed
auto merge of #10316 : klutzy/rust/attr-lint, r=cmr
This patchset makes warning if crate-level attribute is used at other places, obsolete attributed is used, or unknown attribute is used, since they are usually from mistakes. Closes #3348
2 parents 720bcd8 + fa2077a commit c6a87c2

File tree

14 files changed

+160
-55
lines changed

14 files changed

+160
-55
lines changed

src/etc/extract-tests.py

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#[ allow(unused_variable) ];\n
6464
#[ allow(dead_assignment) ];\n
6565
#[ allow(unused_mut) ];\n
66+
#[ allow(attribute_usage) ];\n
6667
#[ feature(macro_rules, globs, struct_variant, managed_boxes) ];\n
6768
""" + block
6869
if xfail:

src/librustc/middle/lint.rs

+108
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub enum lint {
7676
type_overflow,
7777
unused_unsafe,
7878
unsafe_block,
79+
attribute_usage,
7980

8081
managed_heap_memory,
8182
owned_heap_memory,
@@ -244,6 +245,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
244245
default: allow
245246
}),
246247

248+
("attribute_usage",
249+
LintSpec {
250+
lint: attribute_usage,
251+
desc: "detects bad use of attributes",
252+
default: warn
253+
}),
254+
247255
("unused_variable",
248256
LintSpec {
249257
lint: unused_variable,
@@ -790,6 +798,83 @@ fn check_heap_item(cx: &Context, it: &ast::item) {
790798
}
791799
}
792800

801+
static crate_attrs: &'static [&'static str] = &[
802+
"crate_type", "link", "feature", "no_uv", "no_main", "no_std",
803+
"desc", "comment", "license", "copyright", // not used in rustc now
804+
];
805+
806+
807+
static obsolete_attrs: &'static [(&'static str, &'static str)] = &[
808+
("abi", "Use `extern \"abi\" fn` instead"),
809+
("auto_encode", "Use `#[deriving(Encodable)]` instead"),
810+
("auto_decode", "Use `#[deriving(Decodable)]` instead"),
811+
("fast_ffi", "Remove it"),
812+
("fixed_stack_segment", "Remove it"),
813+
("rust_stack", "Remove it"),
814+
];
815+
816+
static other_attrs: &'static [&'static str] = &[
817+
// item-level
818+
"address_insignificant", // can be crate-level too
819+
"allow", "deny", "forbid", "warn", // lint options
820+
"deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability
821+
"crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze",
822+
"no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag",
823+
"packed", "simd", "repr", "deriving", "unsafe_destructor",
824+
825+
//mod-level
826+
"path", "link_name", "link_args", "nolink", "macro_escape", "no_implicit_prelude",
827+
828+
// fn-level
829+
"test", "bench", "should_fail", "ignore", "inline", "lang", "main", "start",
830+
"no_split_stack", "cold",
831+
832+
// internal attribute: bypass privacy inside items
833+
"!resolve_unexported",
834+
];
835+
836+
fn check_crate_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
837+
838+
for attr in attrs.iter() {
839+
let name = attr.node.value.name();
840+
let mut iter = crate_attrs.iter().chain(other_attrs.iter());
841+
if !iter.any(|other_attr| { name.equiv(other_attr) }) {
842+
cx.span_lint(attribute_usage, attr.span, "unknown crate attribute");
843+
}
844+
}
845+
}
846+
847+
fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) {
848+
// check if element has crate-level, obsolete, or any unknown attributes.
849+
850+
for attr in attrs.iter() {
851+
let name = attr.node.value.name();
852+
for crate_attr in crate_attrs.iter() {
853+
if name.equiv(crate_attr) {
854+
let msg = match attr.node.style {
855+
ast::AttrOuter => "crate-level attribute should be an inner attribute: \
856+
add semicolon at end",
857+
ast::AttrInner => "crate-level attribute should be in the root module",
858+
};
859+
cx.span_lint(attribute_usage, attr.span, msg);
860+
return;
861+
}
862+
}
863+
864+
for &(obs_attr, obs_alter) in obsolete_attrs.iter() {
865+
if name.equiv(&obs_attr) {
866+
cx.span_lint(attribute_usage, attr.span,
867+
format!("obsolete attribute: {:s}", obs_alter));
868+
return;
869+
}
870+
}
871+
872+
if !other_attrs.iter().any(|other_attr| { name.equiv(other_attr) }) {
873+
cx.span_lint(attribute_usage, attr.span, "unknown attribute");
874+
}
875+
}
876+
}
877+
793878
fn check_heap_expr(cx: &Context, e: &ast::Expr) {
794879
let ty = ty::expr_ty(cx.tcx, e);
795880
check_heap_type(cx, e.span, ty);
@@ -1110,6 +1195,7 @@ impl<'self> Visitor<()> for Context<'self> {
11101195
check_item_non_uppercase_statics(cx, it);
11111196
check_heap_item(cx, it);
11121197
check_missing_doc_item(cx, it);
1198+
check_attrs_usage(cx, it.attrs);
11131199

11141200
do cx.visit_ids |v| {
11151201
v.visit_item(it, ());
@@ -1119,6 +1205,20 @@ impl<'self> Visitor<()> for Context<'self> {
11191205
}
11201206
}
11211207

1208+
fn visit_foreign_item(&mut self, it: @ast::foreign_item, _: ()) {
1209+
do self.with_lint_attrs(it.attrs) |cx| {
1210+
check_attrs_usage(cx, it.attrs);
1211+
visit::walk_foreign_item(cx, it, ());
1212+
}
1213+
}
1214+
1215+
fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
1216+
do self.with_lint_attrs(i.attrs) |cx| {
1217+
check_attrs_usage(cx, i.attrs);
1218+
visit::walk_view_item(cx, i, ());
1219+
}
1220+
}
1221+
11221222
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
11231223
check_pat_non_uppercase_statics(self, p);
11241224
check_unused_mut_pat(self, p);
@@ -1168,6 +1268,7 @@ impl<'self> Visitor<()> for Context<'self> {
11681268
visit::fk_method(_, _, m) => {
11691269
do self.with_lint_attrs(m.attrs) |cx| {
11701270
check_missing_doc_method(cx, m);
1271+
check_attrs_usage(cx, m.attrs);
11711272

11721273
do cx.visit_ids |v| {
11731274
v.visit_fn(fk, decl, body, span, id, ());
@@ -1179,9 +1280,11 @@ impl<'self> Visitor<()> for Context<'self> {
11791280
}
11801281
}
11811282

1283+
11821284
fn visit_ty_method(&mut self, t: &ast::TypeMethod, _: ()) {
11831285
do self.with_lint_attrs(t.attrs) |cx| {
11841286
check_missing_doc_ty_method(cx, t);
1287+
check_attrs_usage(cx, t.attrs);
11851288

11861289
visit::walk_ty_method(cx, t, ());
11871290
}
@@ -1202,6 +1305,7 @@ impl<'self> Visitor<()> for Context<'self> {
12021305
fn visit_struct_field(&mut self, s: @ast::struct_field, _: ()) {
12031306
do self.with_lint_attrs(s.node.attrs) |cx| {
12041307
check_missing_doc_struct_field(cx, s);
1308+
check_attrs_usage(cx, s.node.attrs);
12051309

12061310
visit::walk_struct_field(cx, s, ());
12071311
}
@@ -1210,6 +1314,7 @@ impl<'self> Visitor<()> for Context<'self> {
12101314
fn visit_variant(&mut self, v: &ast::variant, g: &ast::Generics, _: ()) {
12111315
do self.with_lint_attrs(v.node.attrs) |cx| {
12121316
check_missing_doc_variant(cx, v);
1317+
check_attrs_usage(cx, v.node.attrs);
12131318

12141319
visit::walk_variant(cx, v, g, ());
12151320
}
@@ -1256,6 +1361,9 @@ pub fn check_crate(tcx: ty::ctxt,
12561361
v.visited_outermost = true;
12571362
visit::walk_crate(v, crate, ());
12581363
}
1364+
1365+
check_crate_attrs_usage(cx, crate.attrs);
1366+
12591367
visit::walk_crate(cx, crate, ());
12601368
}
12611369

src/librustpkg/path_util.rs

-2
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,6 @@ pub fn versionize(p: &Path, v: &Version) -> Path {
461461
}
462462

463463
#[cfg(target_os = "win32")]
464-
#[fixed_stack_segment]
465464
pub fn chmod_read_only(p: &Path) -> bool {
466465
unsafe {
467466
do p.with_c_str |src_buf| {
@@ -471,7 +470,6 @@ pub fn chmod_read_only(p: &Path) -> bool {
471470
}
472471

473472
#[cfg(not(target_os = "win32"))]
474-
#[fixed_stack_segment]
475473
pub fn chmod_read_only(p: &Path) -> bool {
476474
unsafe {
477475
do p.with_c_str |src_buf| {

src/libstd/cell.rs

-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
//! Types dealing with dynamic mutability
1212
13-
#[missing_doc];
14-
1513
use prelude::*;
1614
use cast;
1715
use util::NonCopyable;

src/libstd/io/native/process.rs

-1
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,6 @@ fn spawn_process_os(prog: &str, args: &[~str],
365365
use libc::funcs::bsd44::getdtablesize;
366366

367367
mod rustrt {
368-
#[abi = "cdecl"]
369368
extern {
370369
pub fn rust_unset_sigprocmask();
371370
}

src/libstd/vec.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2704,7 +2704,7 @@ mod tests {
27042704
assert_eq!(a.init(), &[11]);
27052705
}
27062706

2707-
#[init]
2707+
#[test]
27082708
#[should_fail]
27092709
fn test_init_empty() {
27102710
let a: ~[int] = ~[];
@@ -2719,7 +2719,7 @@ mod tests {
27192719
assert_eq!(a.initn(2), &[11]);
27202720
}
27212721

2722-
#[init]
2722+
#[test]
27232723
#[should_fail]
27242724
fn test_initn_empty() {
27252725
let a: ~[int] = ~[];

src/libsyntax/ext/auto_encode.rs

-35
This file was deleted.

src/libsyntax/ext/base.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub enum MacResult {
143143
}
144144

145145
pub enum SyntaxExtension {
146-
// #[auto_encode] and such
146+
// #[deriving] and such
147147
ItemDecorator(ItemDecorator),
148148

149149
// Token-tree expanders
@@ -229,12 +229,6 @@ pub fn syntax_expander_table() -> SyntaxEnv {
229229
syntax_expanders.insert(intern(&"format_args"),
230230
builtin_normal_tt_no_ctxt(
231231
ext::format::expand_args));
232-
syntax_expanders.insert(
233-
intern(&"auto_encode"),
234-
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
235-
syntax_expanders.insert(
236-
intern(&"auto_decode"),
237-
@SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
238232
syntax_expanders.insert(intern(&"env"),
239233
builtin_normal_tt_no_ctxt(
240234
ext::env::expand_env));

src/libsyntax/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ pub mod ext {
8383
pub mod concat;
8484
pub mod concat_idents;
8585
pub mod log_syntax;
86-
pub mod auto_encode;
8786
pub mod source_util;
8887

8988
pub mod trace_macros;

src/test/compile-fail/cast-to-bare-fn.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
fn foo(_x: int) { }
1212

13-
#[fixed_stack_segment]
1413
fn main() {
1514
let v: u64 = 5;
1615
let x = foo as extern "C" fn() -> int;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// When denying at the crate level, be sure to not get random warnings from the
12+
// injected intrinsics by the compiler.
13+
14+
#[deny(attribute_usage)];
15+
16+
mod a {
17+
#[crate_type = "bin"]; //~ ERROR: crate-level attribute
18+
}
19+
20+
#[crate_type = "bin"] fn main() {} //~ ERROR: crate-level attribute

src/test/compile-fail/deprecated-auto-code.rs src/test/compile-fail/lint-obsolete-attr.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[auto_encode] //~ ERROR: `#[auto_encode]` is deprecated
12-
#[auto_decode] //~ ERROR: `#[auto_decode]` is deprecated
13-
struct A;
11+
// When denying at the crate level, be sure to not get random warnings from the
12+
// injected intrinsics by the compiler.
13+
14+
#[deny(attribute_usage)];
15+
16+
#[abi="stdcall"] extern {} //~ ERROR: obsolete attribute
17+
18+
#[fixed_stack_segment] fn f() {} //~ ERROR: obsolete attribute
1419

1520
fn main() {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// When denying at the crate level, be sure to not get random warnings from the
12+
// injected intrinsics by the compiler.
13+
14+
#[deny(attribute_usage)];
15+
16+
#[mutable_doc]; //~ ERROR: unknown crate attribute
17+
18+
#[dance] mod a {} //~ ERROR: unknown attribute
19+
20+
#[dance] fn main() {} //~ ERROR: unknown attribute

src/test/run-pass/ifmt.rs

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use std::str;
2323
struct A;
2424
struct B;
2525

26-
#[fmt="foo"]
2726
impl fmt::Signed for A {
2827
fn fmt(_: &A, f: &mut fmt::Formatter) { f.buf.write("aloha".as_bytes()); }
2928
}

0 commit comments

Comments
 (0)