@@ -798,36 +798,65 @@ fn check_heap_item(cx: &Context, it: &ast::item) {
798
798
}
799
799
}
800
800
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
+
806
809
let obsolete_attrs = [
807
810
( "abi" , "extern \" abi\" fn" ) ,
808
811
( "auto_encode" , "#[deriving(Encodable)]" ) ,
809
812
( "auto_decode" , "#[deriving(Decodable)]" ) ,
810
813
] ;
811
814
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 ( ) {
813
836
let name = attr. node . value . name ( ) ;
814
837
for crate_attr in crate_attrs. iter ( ) {
815
838
if name. equiv ( crate_attr) {
816
839
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",
819
842
ast:: AttrInner => "crate-level attribute should be in the root module" ,
820
843
} ;
821
844
cx. span_lint ( attribute_usage, attr. span , msg) ;
845
+ return ;
822
846
}
823
847
}
824
848
825
849
for & ( obs_attr, obs_alter) in obsolete_attrs. iter ( ) {
826
850
if name. equiv ( & obs_attr) {
827
851
cx. span_lint ( attribute_usage, attr. span ,
828
852
format ! ( "obsolete attribute: use `{:s}` instead" , obs_alter) ) ;
853
+ return ;
829
854
}
830
855
}
856
+
857
+ if !other_attrs. iter ( ) . any ( |other_attr| { name. equiv ( other_attr) } ) {
858
+ cx. span_lint ( attribute_usage, attr. span , "unknown attribute" ) ;
859
+ }
831
860
}
832
861
}
833
862
@@ -1151,7 +1180,7 @@ impl<'self> Visitor<()> for Context<'self> {
1151
1180
check_item_non_uppercase_statics ( cx, it) ;
1152
1181
check_heap_item ( cx, it) ;
1153
1182
check_missing_doc_item ( cx, it) ;
1154
- check_item_attribute_usage ( cx, it) ;
1183
+ check_attrs_usage ( cx, it. attrs ) ;
1155
1184
1156
1185
do cx. visit_ids |v| {
1157
1186
v. visit_item ( it, ( ) ) ;
@@ -1161,6 +1190,20 @@ impl<'self> Visitor<()> for Context<'self> {
1161
1190
}
1162
1191
}
1163
1192
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
+
1164
1207
fn visit_pat ( & mut self , p : & ast:: Pat , _: ( ) ) {
1165
1208
check_pat_non_uppercase_statics ( self , p) ;
1166
1209
check_unused_mut_pat ( self , p) ;
@@ -1210,6 +1253,7 @@ impl<'self> Visitor<()> for Context<'self> {
1210
1253
visit:: fk_method( _, _, m) => {
1211
1254
do self . with_lint_attrs ( m. attrs ) |cx| {
1212
1255
check_missing_doc_method ( cx, m) ;
1256
+ check_attrs_usage ( cx, m. attrs ) ;
1213
1257
1214
1258
do cx. visit_ids |v| {
1215
1259
v. visit_fn ( fk, decl, body, span, id, ( ) ) ;
@@ -1221,9 +1265,11 @@ impl<'self> Visitor<()> for Context<'self> {
1221
1265
}
1222
1266
}
1223
1267
1268
+
1224
1269
fn visit_ty_method ( & mut self , t : & ast:: TypeMethod , _: ( ) ) {
1225
1270
do self . with_lint_attrs ( t. attrs ) |cx| {
1226
1271
check_missing_doc_ty_method ( cx, t) ;
1272
+ check_attrs_usage ( cx, t. attrs ) ;
1227
1273
1228
1274
visit:: walk_ty_method ( cx, t, ( ) ) ;
1229
1275
}
@@ -1244,6 +1290,7 @@ impl<'self> Visitor<()> for Context<'self> {
1244
1290
fn visit_struct_field ( & mut self , s : @ast:: struct_field , _: ( ) ) {
1245
1291
do self . with_lint_attrs ( s. node . attrs ) |cx| {
1246
1292
check_missing_doc_struct_field ( cx, s) ;
1293
+ check_attrs_usage ( cx, s. node . attrs ) ;
1247
1294
1248
1295
visit:: walk_struct_field ( cx, s, ( ) ) ;
1249
1296
}
@@ -1252,6 +1299,7 @@ impl<'self> Visitor<()> for Context<'self> {
1252
1299
fn visit_variant ( & mut self , v : & ast:: variant , g : & ast:: Generics , _: ( ) ) {
1253
1300
do self . with_lint_attrs ( v. node . attrs ) |cx| {
1254
1301
check_missing_doc_variant ( cx, v) ;
1302
+ check_attrs_usage ( cx, v. node . attrs ) ;
1255
1303
1256
1304
visit:: walk_variant ( cx, v, g, ( ) ) ;
1257
1305
}
0 commit comments