@@ -66,6 +66,10 @@ pub struct LintStore {
66
66
67
67
/// Current levels of each lint, and where they were set.
68
68
levels : HashMap < LintId , LevelSource > ,
69
+
70
+ /// Map of registered lint groups to what lints they expand to. The bool
71
+ /// is true if the lint group was added by a plugin.
72
+ lint_groups : HashMap < & ' static str , ( Vec < LintId > , bool ) > ,
69
73
}
70
74
71
75
impl LintStore {
@@ -90,13 +94,18 @@ impl LintStore {
90
94
passes : Some ( vec ! ( ) ) ,
91
95
by_name : HashMap :: new ( ) ,
92
96
levels : HashMap :: new ( ) ,
97
+ lint_groups : HashMap :: new ( ) ,
93
98
}
94
99
}
95
100
96
101
pub fn get_lints < ' t > ( & ' t self ) -> & ' t [ ( & ' static Lint , bool ) ] {
97
102
self . lints . as_slice ( )
98
103
}
99
104
105
+ pub fn get_lint_groups < ' t > ( & ' t self ) -> Vec < ( & ' static str , Vec < LintId > , bool ) > {
106
+ self . lint_groups . iter ( ) . map ( |( k, & ( ref v, b) ) | ( * k, v. clone ( ) , b) ) . collect ( )
107
+ }
108
+
100
109
pub fn register_pass ( & mut self , sess : Option < & Session > ,
101
110
from_plugin : bool , pass : LintPassObject ) {
102
111
for & lint in pass. get_lints ( ) . iter ( ) {
@@ -123,6 +132,25 @@ impl LintStore {
123
132
self . passes . get_mut_ref ( ) . push ( pass) ;
124
133
}
125
134
135
+ pub fn register_group ( & mut self , sess : Option < & Session > ,
136
+ from_plugin : bool , name : & ' static str ,
137
+ to : Vec < LintId > ) {
138
+ let new = self . lint_groups . insert ( name, ( to, from_plugin) ) ;
139
+
140
+ if !new {
141
+ let msg = format ! ( "duplicate specification of lint group {}" , name) ;
142
+ match ( sess, from_plugin) {
143
+ // We load builtin lints first, so a duplicate is a compiler bug.
144
+ // Use early_error when handling -W help with no crate.
145
+ ( None , _) => early_error ( msg. as_slice ( ) ) ,
146
+ ( Some ( sess) , false ) => sess. bug ( msg. as_slice ( ) ) ,
147
+
148
+ // A duplicate name from a plugin is a user error.
149
+ ( Some ( sess) , true ) => sess. err ( msg. as_slice ( ) ) ,
150
+ }
151
+ }
152
+ }
153
+
126
154
pub fn register_builtin ( & mut self , sess : Option < & Session > ) {
127
155
macro_rules! add_builtin ( ( $sess: ident, $( $name: ident) ,* , ) => (
128
156
{ $(
@@ -136,6 +164,10 @@ impl LintStore {
136
164
) * }
137
165
) )
138
166
167
+ macro_rules! add_lint_group ( ( $sess: ident, $name: expr, $( $lint: ident) ,* ) => (
168
+ self . register_group( $sess, false , $name, vec![ $( LintId :: of( builtin:: $lint) ) ,* ] ) ;
169
+ ) )
170
+
139
171
add_builtin ! ( sess,
140
172
HardwiredLints ,
141
173
WhileTrue ,
@@ -162,6 +194,13 @@ impl LintStore {
162
194
MissingDoc ,
163
195
)
164
196
197
+ add_lint_group ! ( sess, "bad_style" ,
198
+ NON_CAMEL_CASE_TYPES , NON_SNAKE_CASE , NON_UPPERCASE_STATICS )
199
+
200
+ add_lint_group ! ( sess, "unused" ,
201
+ UNUSED_IMPORTS , UNUSED_VARIABLE , DEAD_ASSIGNMENT , DEAD_CODE ,
202
+ UNUSED_MUT , UNREACHABLE_CODE )
203
+
165
204
// We have one lint pass defined in this module.
166
205
self . register_pass ( sess, false , box GatherNodeLevels as LintPassObject ) ;
167
206
}
@@ -170,8 +209,20 @@ impl LintStore {
170
209
for & ( ref lint_name, level) in sess. opts . lint_opts . iter ( ) {
171
210
match self . by_name . find_equiv ( & lint_name. as_slice ( ) ) {
172
211
Some ( & lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
173
- None => sess. err ( format ! ( "unknown {} flag: {}" ,
174
- level. as_str( ) , lint_name) . as_slice ( ) ) ,
212
+ None => {
213
+ match self . lint_groups . iter ( ) . map ( |( & x, & ( ref y, _) ) | ( x, y. clone ( ) ) )
214
+ . collect :: < HashMap < & ' static str , Vec < LintId > > > ( )
215
+ . find_equiv ( & lint_name. as_slice ( ) ) {
216
+ Some ( v) => {
217
+ v. iter ( )
218
+ . map ( |lint_id : & LintId |
219
+ self . set_level ( * lint_id, ( level, CommandLine ) ) )
220
+ . collect :: < Vec < ( ) > > ( ) ;
221
+ }
222
+ None => sess. err ( format ! ( "unknown {} flag: {}" ,
223
+ level. as_str( ) , lint_name) . as_slice ( ) ) ,
224
+ }
225
+ }
175
226
}
176
227
}
177
228
}
@@ -305,7 +356,7 @@ impl<'a> Context<'a> {
305
356
krate : krate,
306
357
exported_items : exported_items,
307
358
lints : lint_store,
308
- level_stack : vec ! ( ) ,
359
+ level_stack : vec ! [ ] ,
309
360
node_levels : RefCell :: new ( HashMap :: new ( ) ) ,
310
361
}
311
362
}
@@ -359,35 +410,46 @@ impl<'a> Context<'a> {
359
410
let mut pushed = 0 u;
360
411
361
412
for result in gather_attrs ( attrs) . move_iter ( ) {
362
- let ( lint_id , level , span ) = match result {
413
+ let v = match result {
363
414
Err ( span) => {
364
415
self . tcx . sess . span_err ( span, "malformed lint attribute" ) ;
365
416
continue ;
366
417
}
367
418
Ok ( ( lint_name, level, span) ) => {
368
419
match self . lints . by_name . find_equiv ( & lint_name. get ( ) ) {
369
- Some ( & lint_id) => ( lint_id, level, span) ,
420
+ Some ( & lint_id) => vec ! [ ( lint_id, level, span) ] ,
370
421
None => {
371
- self . span_lint ( builtin:: UNRECOGNIZED_LINT , span,
372
- format ! ( "unknown `{}` attribute: `{}`" ,
373
- level. as_str( ) , lint_name) . as_slice ( ) ) ;
374
- continue ;
422
+ match self . lints . lint_groups . find_equiv ( & lint_name. get ( ) ) {
423
+ Some ( & ( ref v, _) ) => v. iter ( )
424
+ . map ( |lint_id : & LintId |
425
+ ( * lint_id, level, span) )
426
+ . collect ( ) ,
427
+ None => {
428
+ self . span_lint ( builtin:: UNRECOGNIZED_LINT , span,
429
+ format ! ( "unknown `{}` attribute: `{}`" ,
430
+ level. as_str( ) , lint_name) . as_slice ( ) ) ;
431
+ continue ;
432
+ }
433
+ }
375
434
}
376
435
}
377
436
}
378
437
} ;
379
438
380
- let now = self . lints . get_level_source ( lint_id) . val0 ( ) ;
381
- if now == Forbid && level != Forbid {
382
- let lint_name = lint_id. as_str ( ) ;
383
- self . tcx . sess . span_err ( span,
384
- format ! ( "{}({}) overruled by outer forbid({})" ,
385
- level. as_str( ) , lint_name, lint_name) . as_slice ( ) ) ;
386
- } else if now != level {
387
- let src = self . lints . get_level_source ( lint_id) . val1 ( ) ;
388
- self . level_stack . push ( ( lint_id, ( now, src) ) ) ;
389
- pushed += 1 ;
390
- self . lints . set_level ( lint_id, ( level, Node ( span) ) ) ;
439
+ for ( lint_id, level, span) in v. move_iter ( ) {
440
+ let now = self . lints . get_level_source ( lint_id) . val0 ( ) ;
441
+ if now == Forbid && level != Forbid {
442
+ let lint_name = lint_id. as_str ( ) ;
443
+ self . tcx . sess . span_err ( span,
444
+ format ! ( "{}({}) overruled by outer forbid({})" ,
445
+ level. as_str( ) , lint_name,
446
+ lint_name) . as_slice ( ) ) ;
447
+ } else if now != level {
448
+ let src = self . lints . get_level_source ( lint_id) . val1 ( ) ;
449
+ self . level_stack . push ( ( lint_id, ( now, src) ) ) ;
450
+ pushed += 1 ;
451
+ self . lints . set_level ( lint_id, ( level, Node ( span) ) ) ;
452
+ }
391
453
}
392
454
}
393
455
0 commit comments