12
12
use driver:: session;
13
13
use middle:: ty;
14
14
use middle:: pat_util;
15
+ use metadata:: csearch;
15
16
use util:: ppaux:: { ty_to_str} ;
16
17
17
18
use std:: cmp;
@@ -27,7 +28,7 @@ use std::u8;
27
28
use extra:: smallintmap:: SmallIntMap ;
28
29
use syntax:: ast_map;
29
30
use syntax:: attr;
30
- use syntax:: attr:: AttrMetaMethods ;
31
+ use syntax:: attr:: { AttrMetaMethods , AttributeMethods } ;
31
32
use syntax:: codemap:: Span ;
32
33
use syntax:: codemap;
33
34
use syntax:: parse:: token;
@@ -97,6 +98,10 @@ pub enum lint {
97
98
missing_doc,
98
99
unreachable_code,
99
100
101
+ deprecated,
102
+ experimental,
103
+ unstable,
104
+
100
105
warnings,
101
106
}
102
107
@@ -281,6 +286,27 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
281
286
default : warn
282
287
} ) ,
283
288
289
+ ( "deprecated" ,
290
+ LintSpec {
291
+ lint : deprecated,
292
+ desc : "detects use of #[deprecated] items" ,
293
+ default : warn
294
+ } ) ,
295
+
296
+ ( "experimental" ,
297
+ LintSpec {
298
+ lint : experimental,
299
+ desc : "detects use of #[experimental] items" ,
300
+ default : warn
301
+ } ) ,
302
+
303
+ ( "unstable" ,
304
+ LintSpec {
305
+ lint : unstable,
306
+ desc : "detects use of #[unstable] items (incl. items with no stability attribute)" ,
307
+ default : allow
308
+ } ) ,
309
+
284
310
( "warnings" ,
285
311
LintSpec {
286
312
lint : warnings,
@@ -1375,6 +1401,107 @@ fn lint_missing_doc() -> @mut OuterLint {
1375
1401
@mut MissingDocLintVisitor { stopping_on_items : false } as @mut OuterLint
1376
1402
}
1377
1403
1404
+ /// Checks for use of items with #[deprecated], #[experimental] and
1405
+ /// #[unstable] (or none of them) attributes.
1406
+ struct StabilityLintVisitor { stopping_on_items : bool }
1407
+
1408
+ impl StabilityLintVisitor {
1409
+ fn handle_def ( & mut self , sp : Span , def : & ast:: Def , cx : @mut Context ) {
1410
+ let id = ast_util:: def_id_of_def ( * def) ;
1411
+
1412
+ let stability = if ast_util:: is_local ( id) {
1413
+ // this crate
1414
+ match cx. tcx . items . find ( & id. node ) {
1415
+ Some ( ast_node) => {
1416
+ let s = do ast_node. with_attrs |attrs| {
1417
+ do attrs. map_move |a| {
1418
+ attr:: find_stability ( a. iter ( ) . map ( |a| a. meta ( ) ) )
1419
+ }
1420
+ } ;
1421
+ match s {
1422
+ Some ( s) => s,
1423
+
1424
+ // no possibility of having attributes
1425
+ // (e.g. it's a local variable), so just
1426
+ // ignore it.
1427
+ None => return
1428
+ }
1429
+ }
1430
+ _ => cx. tcx . sess . bug ( fmt ! ( "handle_def: %? not found" , id) )
1431
+ }
1432
+ } else {
1433
+ // cross-crate
1434
+
1435
+ let mut s = None ;
1436
+ // run through all the attributes and take the first
1437
+ // stability one.
1438
+ do csearch:: get_item_attrs ( cx. tcx . cstore , id) |meta_items| {
1439
+ if s. is_none ( ) {
1440
+ s = attr:: find_stability ( meta_items. move_iter ( ) )
1441
+ }
1442
+ }
1443
+ s
1444
+ } ;
1445
+
1446
+ let ( lint, label) = match stability {
1447
+ // no stability attributes == Unstable
1448
+ None => ( unstable, "unmarked" ) ,
1449
+ Some ( attr:: Stability { level : attr:: Unstable , _ } ) => ( unstable, "unstable" ) ,
1450
+ Some ( attr:: Stability { level : attr:: Experimental , _ } ) => {
1451
+ ( experimental, "experimental" )
1452
+ }
1453
+ Some ( attr:: Stability { level : attr:: Deprecated , _ } ) => ( deprecated, "deprecated" ) ,
1454
+ _ => return
1455
+ } ;
1456
+
1457
+ let msg = match stability {
1458
+ Some ( attr:: Stability { text : Some ( ref s) , _ } ) => {
1459
+ fmt ! ( "use of %s item: %s" , label, * s)
1460
+ }
1461
+ _ => fmt ! ( "use of %s item" , label)
1462
+ } ;
1463
+
1464
+ cx. span_lint ( lint, sp, msg) ;
1465
+ }
1466
+ }
1467
+
1468
+ impl SubitemStoppableVisitor for StabilityLintVisitor {
1469
+ fn is_running_on_items ( & mut self ) -> bool { !self . stopping_on_items }
1470
+ }
1471
+
1472
+ impl Visitor < @mut Context > for StabilityLintVisitor {
1473
+ fn visit_item ( & mut self , i : @ast:: item , e : @mut Context ) {
1474
+ self . OVERRIDE_visit_item ( i, e) ;
1475
+ }
1476
+
1477
+ fn visit_fn ( & mut self , fk : & visit:: fn_kind , fd : & ast:: fn_decl ,
1478
+ b : & ast:: Block , s : Span , n : ast:: NodeId , e : @mut Context ) {
1479
+ self . OVERRIDE_visit_fn ( fk, fd, b, s, n, e) ;
1480
+ }
1481
+
1482
+ fn visit_expr ( & mut self , ex : @ast:: Expr , cx : @mut Context ) {
1483
+ match ex. node {
1484
+ ast:: ExprMethodCall ( * ) |
1485
+ ast:: ExprPath ( * ) |
1486
+ ast:: ExprStruct ( * ) => {
1487
+ match cx. tcx . def_map . find ( & ex. id ) {
1488
+ Some ( def) => self . handle_def ( ex. span , def, cx) ,
1489
+ None => { }
1490
+ }
1491
+ }
1492
+ _ => { }
1493
+ }
1494
+
1495
+ visit:: walk_expr ( self , ex, cx)
1496
+ }
1497
+ }
1498
+
1499
+ outer_lint_boilerplate_impl ! ( StabilityLintVisitor )
1500
+
1501
+ fn lint_stability ( ) -> @mut OuterLint {
1502
+ @mut StabilityLintVisitor { stopping_on_items : false } as @mut OuterLint
1503
+ }
1504
+
1378
1505
struct LintCheckVisitor ;
1379
1506
1380
1507
impl Visitor < @mut Context > for LintCheckVisitor {
@@ -1458,6 +1585,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) {
1458
1585
cx. add_old_lint ( lint_unused_mut ( ) ) ;
1459
1586
cx. add_old_lint ( lint_unnecessary_allocations ( ) ) ;
1460
1587
cx. add_old_lint ( lint_missing_doc ( ) ) ;
1588
+ cx. add_old_lint ( lint_stability ( ) ) ;
1461
1589
cx. add_lint ( lint_session ( cx) ) ;
1462
1590
1463
1591
// Actually perform the lint checks (iterating the ast)
0 commit comments