@@ -76,6 +76,7 @@ pub enum lint {
76
76
type_overflow,
77
77
unused_unsafe,
78
78
unsafe_block,
79
+ attribute_usage,
79
80
80
81
managed_heap_memory,
81
82
owned_heap_memory,
@@ -244,6 +245,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
244
245
default : allow
245
246
} ) ,
246
247
248
+ ( "attribute_usage" ,
249
+ LintSpec {
250
+ lint : attribute_usage,
251
+ desc : "detects bad use of attributes" ,
252
+ default : warn
253
+ } ) ,
254
+
247
255
( "unused_variable" ,
248
256
LintSpec {
249
257
lint : unused_variable,
@@ -790,6 +798,83 @@ fn check_heap_item(cx: &Context, it: &ast::item) {
790
798
}
791
799
}
792
800
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
+
793
878
fn check_heap_expr ( cx : & Context , e : & ast:: Expr ) {
794
879
let ty = ty:: expr_ty ( cx. tcx , e) ;
795
880
check_heap_type ( cx, e. span , ty) ;
@@ -1110,6 +1195,7 @@ impl<'self> Visitor<()> for Context<'self> {
1110
1195
check_item_non_uppercase_statics ( cx, it) ;
1111
1196
check_heap_item ( cx, it) ;
1112
1197
check_missing_doc_item ( cx, it) ;
1198
+ check_attrs_usage ( cx, it. attrs ) ;
1113
1199
1114
1200
do cx. visit_ids |v| {
1115
1201
v. visit_item ( it, ( ) ) ;
@@ -1119,6 +1205,20 @@ impl<'self> Visitor<()> for Context<'self> {
1119
1205
}
1120
1206
}
1121
1207
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
+
1122
1222
fn visit_pat ( & mut self , p : & ast:: Pat , _: ( ) ) {
1123
1223
check_pat_non_uppercase_statics ( self , p) ;
1124
1224
check_unused_mut_pat ( self , p) ;
@@ -1168,6 +1268,7 @@ impl<'self> Visitor<()> for Context<'self> {
1168
1268
visit:: fk_method( _, _, m) => {
1169
1269
do self . with_lint_attrs ( m. attrs ) |cx| {
1170
1270
check_missing_doc_method ( cx, m) ;
1271
+ check_attrs_usage ( cx, m. attrs ) ;
1171
1272
1172
1273
do cx. visit_ids |v| {
1173
1274
v. visit_fn ( fk, decl, body, span, id, ( ) ) ;
@@ -1179,9 +1280,11 @@ impl<'self> Visitor<()> for Context<'self> {
1179
1280
}
1180
1281
}
1181
1282
1283
+
1182
1284
fn visit_ty_method ( & mut self , t : & ast:: TypeMethod , _: ( ) ) {
1183
1285
do self . with_lint_attrs ( t. attrs ) |cx| {
1184
1286
check_missing_doc_ty_method ( cx, t) ;
1287
+ check_attrs_usage ( cx, t. attrs ) ;
1185
1288
1186
1289
visit:: walk_ty_method ( cx, t, ( ) ) ;
1187
1290
}
@@ -1202,6 +1305,7 @@ impl<'self> Visitor<()> for Context<'self> {
1202
1305
fn visit_struct_field ( & mut self , s : @ast:: struct_field , _: ( ) ) {
1203
1306
do self . with_lint_attrs ( s. node . attrs ) |cx| {
1204
1307
check_missing_doc_struct_field ( cx, s) ;
1308
+ check_attrs_usage ( cx, s. node . attrs ) ;
1205
1309
1206
1310
visit:: walk_struct_field ( cx, s, ( ) ) ;
1207
1311
}
@@ -1210,6 +1314,7 @@ impl<'self> Visitor<()> for Context<'self> {
1210
1314
fn visit_variant ( & mut self , v : & ast:: variant , g : & ast:: Generics , _: ( ) ) {
1211
1315
do self . with_lint_attrs ( v. node . attrs ) |cx| {
1212
1316
check_missing_doc_variant ( cx, v) ;
1317
+ check_attrs_usage ( cx, v. node . attrs ) ;
1213
1318
1214
1319
visit:: walk_variant ( cx, v, g, ( ) ) ;
1215
1320
}
@@ -1256,6 +1361,9 @@ pub fn check_crate(tcx: ty::ctxt,
1256
1361
v. visited_outermost = true ;
1257
1362
visit:: walk_crate ( v, crate , ( ) ) ;
1258
1363
}
1364
+
1365
+ check_crate_attrs_usage ( cx, crate . attrs) ;
1366
+
1259
1367
visit:: walk_crate ( cx, crate , ( ) ) ;
1260
1368
}
1261
1369
0 commit comments