@@ -72,7 +72,7 @@ use syntax::parse::token;
72
72
use syntax:: visit:: Visitor ;
73
73
use syntax:: { ast, ast_util, visit} ;
74
74
75
- #[ deriving( Clone , Eq , Ord , TotalEq , TotalOrd ) ]
75
+ #[ deriving( Clone , Show , Eq , Ord , TotalEq , TotalOrd , Hash ) ]
76
76
pub enum Lint {
77
77
CTypes ,
78
78
UnusedImports ,
@@ -94,6 +94,7 @@ pub enum Lint {
94
94
UnknownFeatures ,
95
95
UnknownCrateType ,
96
96
UnsignedNegate ,
97
+ VariantSizeDifference ,
97
98
98
99
ManagedHeapMemory ,
99
100
OwnedHeapMemory ,
@@ -147,8 +148,9 @@ pub struct LintSpec {
147
148
148
149
pub type LintDict = HashMap < & ' static str , LintSpec > ;
149
150
151
+ // this is public for the lints that run in trans
150
152
#[ deriving( Eq ) ]
151
- enum LintSource {
153
+ pub enum LintSource {
152
154
Node ( Span ) ,
153
155
Default ,
154
156
CommandLine
@@ -407,6 +409,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
407
409
default : Warn
408
410
} ) ,
409
411
412
+ ( "variant_size_difference" ,
413
+ LintSpec {
414
+ lint : VariantSizeDifference ,
415
+ desc : "detects enums with widely varying variant sizes" ,
416
+ default : Allow ,
417
+ } ) ,
418
+
410
419
( "unused_must_use" ,
411
420
LintSpec {
412
421
lint : UnusedMustUse ,
@@ -445,30 +454,78 @@ pub fn get_lint_dict() -> LintDict {
445
454
}
446
455
447
456
struct Context < ' a > {
448
- // All known lint modes (string versions)
457
+ /// All known lint modes (string versions)
449
458
dict : LintDict ,
450
- // Current levels of each lint warning
459
+ /// Current levels of each lint warning
451
460
cur : SmallIntMap < ( Level , LintSource ) > ,
452
- // context we're checking in (used to access fields like sess)
461
+ /// Context we're checking in (used to access fields like sess)
453
462
tcx : & ' a ty:: ctxt ,
454
- // Items exported by the crate; used by the missing_doc lint.
463
+ /// Items exported by the crate; used by the missing_doc lint.
455
464
exported_items : & ' a privacy:: ExportedItems ,
456
- // The id of the current `ast::StructDef` being walked.
465
+ /// The id of the current `ast::StructDef` being walked.
457
466
cur_struct_def_id : ast:: NodeId ,
458
- // Whether some ancestor of the current node was marked
459
- // #[doc(hidden)].
467
+ /// Whether some ancestor of the current node was marked
468
+ /// #[doc(hidden)].
460
469
is_doc_hidden : bool ,
461
470
462
- // When recursing into an attributed node of the ast which modifies lint
463
- // levels, this stack keeps track of the previous lint levels of whatever
464
- // was modified.
471
+ /// When recursing into an attributed node of the ast which modifies lint
472
+ /// levels, this stack keeps track of the previous lint levels of whatever
473
+ /// was modified.
465
474
lint_stack : Vec < ( Lint , Level , LintSource ) > ,
466
475
467
- // id of the last visited negated expression
476
+ /// Id of the last visited negated expression
468
477
negated_expr_id : ast:: NodeId ,
469
478
470
- // ids of structs/enums which have been checked for raw_pointer_deriving
479
+ /// Ids of structs/enums which have been checked for raw_pointer_deriving
471
480
checked_raw_pointers : NodeSet ,
481
+
482
+ /// Level of lints for certain NodeIds, stored here because the body of
483
+ /// the lint needs to run in trans.
484
+ node_levels : HashMap < ( ast:: NodeId , Lint ) , ( Level , LintSource ) > ,
485
+ }
486
+
487
+ pub fn emit_lint ( level : Level , src : LintSource , msg : & str , span : Span ,
488
+ lint_str : & str , tcx : & ty:: ctxt ) {
489
+ if level == Allow { return }
490
+
491
+ let mut note = None ;
492
+ let msg = match src {
493
+ Default => {
494
+ format ! ( "{}, \\ #[{}({})] on by default" , msg,
495
+ level_to_str( level) , lint_str)
496
+ } ,
497
+ CommandLine => {
498
+ format ! ( "{} [-{} {}]" , msg,
499
+ match level {
500
+ Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
501
+ Allow => fail!( )
502
+ } , lint_str. replace( "_" , "-" ) )
503
+ } ,
504
+ Node ( src) => {
505
+ note = Some ( src) ;
506
+ msg. to_str ( )
507
+ }
508
+ } ;
509
+
510
+ match level {
511
+ Warn => { tcx. sess . span_warn ( span, msg. as_slice ( ) ) ; }
512
+ Deny | Forbid => { tcx. sess . span_err ( span, msg. as_slice ( ) ) ; }
513
+ Allow => fail ! ( ) ,
514
+ }
515
+
516
+ for & span in note. iter ( ) {
517
+ tcx. sess . span_note ( span, "lint level defined here" ) ;
518
+ }
519
+ }
520
+
521
+ pub fn lint_to_str ( lint : Lint ) -> & ' static str {
522
+ for & ( name, lspec) in lint_table. iter ( ) {
523
+ if lspec. lint == lint {
524
+ return name;
525
+ }
526
+ }
527
+
528
+ fail ! ( "unrecognized lint: {}" , lint) ;
472
529
}
473
530
474
531
impl < ' a > Context < ' a > {
@@ -500,7 +557,7 @@ impl<'a> Context<'a> {
500
557
return * k;
501
558
}
502
559
}
503
- fail ! ( "unregistered lint {:? }" , lint) ;
560
+ fail ! ( "unregistered lint {}" , lint) ;
504
561
}
505
562
506
563
fn span_lint ( & self , lint : Lint , span : Span , msg : & str ) {
@@ -509,37 +566,8 @@ impl<'a> Context<'a> {
509
566
Some ( & ( Warn , src) ) => ( self . get_level ( Warnings ) , src) ,
510
567
Some ( & pair) => pair,
511
568
} ;
512
- if level == Allow { return }
513
-
514
- let mut note = None ;
515
- let msg = match src {
516
- Default => {
517
- format_strbuf ! ( "{}, \\ #[{}({})] on by default" ,
518
- msg,
519
- level_to_str( level) ,
520
- self . lint_to_str( lint) )
521
- } ,
522
- CommandLine => {
523
- format ! ( "{} [-{} {}]" , msg,
524
- match level {
525
- Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
526
- Allow => fail!( )
527
- } , self . lint_to_str( lint) . replace( "_" , "-" ) )
528
- } ,
529
- Node ( src) => {
530
- note = Some ( src) ;
531
- msg. to_str ( )
532
- }
533
- } ;
534
- match level {
535
- Warn => self . tcx . sess . span_warn ( span, msg. as_slice ( ) ) ,
536
- Deny | Forbid => self . tcx . sess . span_err ( span, msg. as_slice ( ) ) ,
537
- Allow => fail ! ( ) ,
538
- }
539
569
540
- for & span in note. iter ( ) {
541
- self . tcx . sess . span_note ( span, "lint level defined here" ) ;
542
- }
570
+ emit_lint ( level, src, msg, span, self . lint_to_str ( lint) , self . tcx ) ;
543
571
}
544
572
545
573
/**
@@ -618,8 +646,8 @@ impl<'a> Context<'a> {
618
646
}
619
647
}
620
648
621
- // Check that every lint from the list of attributes satisfies `f`.
622
- // Return true if that's the case. Otherwise return false.
649
+ /// Check that every lint from the list of attributes satisfies `f`.
650
+ /// Return true if that's the case. Otherwise return false.
623
651
pub fn each_lint ( sess : & session:: Session ,
624
652
attrs : & [ ast:: Attribute ] ,
625
653
f : |@ast:: MetaItem , Level , InternedString | -> bool)
@@ -653,8 +681,8 @@ pub fn each_lint(sess: &session::Session,
653
681
true
654
682
}
655
683
656
- // Check from a list of attributes if it contains the appropriate
657
- // `#[level(lintname)]` attribute (e.g. `#[allow(dead_code)]).
684
+ /// Check from a list of attributes if it contains the appropriate
685
+ /// `#[level(lintname)]` attribute (e.g. `#[allow(dead_code)]).
658
686
pub fn contains_lint ( attrs : & [ ast:: Attribute ] ,
659
687
level : Level ,
660
688
lintname : & ' static str )
@@ -1739,9 +1767,24 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
1739
1767
cx. span_lint ( lint, e. span , msg. as_slice ( ) ) ;
1740
1768
}
1741
1769
1770
+ fn check_enum_variant_sizes ( cx : & mut Context , it : & ast:: Item ) {
1771
+ match it. node {
1772
+ ast:: ItemEnum ( ..) => {
1773
+ match cx. cur . find ( & ( VariantSizeDifference as uint ) ) {
1774
+ Some ( & ( lvl, src) ) if lvl != Allow => {
1775
+ cx. node_levels . insert ( ( it. id , VariantSizeDifference ) , ( lvl, src) ) ;
1776
+ } ,
1777
+ _ => { }
1778
+ }
1779
+ } ,
1780
+ _ => { }
1781
+ }
1782
+ }
1783
+
1742
1784
impl < ' a > Visitor < ( ) > for Context < ' a > {
1743
1785
fn visit_item ( & mut self , it : & ast:: Item , _: ( ) ) {
1744
1786
self . with_lint_attrs ( it. attrs . as_slice ( ) , |cx| {
1787
+ check_enum_variant_sizes ( cx, it) ;
1745
1788
check_item_ctypes ( cx, it) ;
1746
1789
check_item_non_camel_case_types ( cx, it) ;
1747
1790
check_item_non_uppercase_statics ( cx, it) ;
@@ -1933,6 +1976,7 @@ pub fn check_crate(tcx: &ty::ctxt,
1933
1976
lint_stack : Vec :: new ( ) ,
1934
1977
negated_expr_id : -1 ,
1935
1978
checked_raw_pointers : NodeSet :: new ( ) ,
1979
+ node_levels : HashMap :: new ( ) ,
1936
1980
} ;
1937
1981
1938
1982
// Install default lint levels, followed by the command line levels, and
@@ -1969,13 +2013,11 @@ pub fn check_crate(tcx: &ty::ctxt,
1969
2013
// in the iteration code.
1970
2014
for ( id, v) in tcx. sess . lints . borrow ( ) . iter ( ) {
1971
2015
for & ( lint, span, ref msg) in v. iter ( ) {
1972
- tcx. sess . span_bug ( span,
1973
- format ! ( "unprocessed lint {:?} at {}: {}" ,
1974
- lint,
1975
- tcx. map. node_to_str( * id) ,
1976
- * msg) . as_slice ( ) )
2016
+ tcx. sess . span_bug ( span, format ! ( "unprocessed lint {} at {}: {}" ,
2017
+ lint, tcx. map. node_to_str( * id) , * msg) . as_slice ( ) )
1977
2018
}
1978
2019
}
1979
2020
1980
2021
tcx. sess . abort_if_errors ( ) ;
2022
+ * tcx. node_lint_levels . borrow_mut ( ) = cx. node_levels ;
1981
2023
}
0 commit comments