@@ -41,7 +41,7 @@ use std::default::Default as StdDefault;
41
41
use std:: mem;
42
42
use syntax:: ast_util:: { self , IdVisitingOperation } ;
43
43
use syntax:: attr:: { self , AttrMetaMethods } ;
44
- use syntax:: codemap:: Span ;
44
+ use syntax:: codemap:: { Span , MultiSpan } ;
45
45
use syntax:: errors:: DiagnosticBuilder ;
46
46
use syntax:: parse:: token:: InternedString ;
47
47
use syntax:: ast;
@@ -309,6 +309,9 @@ pub struct LateContext<'a, 'tcx: 'a> {
309
309
/// The store of registered lints.
310
310
lints : LintStore ,
311
311
312
+ /// Sink to collect and fold consecutive lints together
313
+ collapsed_lints : Vec < ( LintId , String , LevelSource , Vec < Span > ) > ,
314
+
312
315
/// When recursing into an attributed node of the ast which modifies lint
313
316
/// levels, this stack keeps track of the previous lint levels of whatever
314
317
/// was modified.
@@ -331,6 +334,9 @@ pub struct EarlyContext<'a> {
331
334
/// The store of registered lints.
332
335
lints : LintStore ,
333
336
337
+ /// Sink to collect and fold consecutive lints together
338
+ collapsed_lints : Vec < ( LintId , String , LevelSource , Vec < Span > ) > ,
339
+
334
340
/// When recursing into an attributed node of the ast which modifies lint
335
341
/// levels, this stack keeps track of the previous lint levels of whatever
336
342
/// was modified.
@@ -402,7 +408,7 @@ pub fn raw_emit_lint(sess: &Session,
402
408
lints : & LintStore ,
403
409
lint : & ' static Lint ,
404
410
lvlsrc : LevelSource ,
405
- span : Option < Span > ,
411
+ span : Option < MultiSpan > ,
406
412
msg : & str ) {
407
413
raw_struct_lint ( sess, lints, lint, lvlsrc, span, msg) . emit ( ) ;
408
414
}
@@ -411,7 +417,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
411
417
lints : & LintStore ,
412
418
lint : & ' static Lint ,
413
419
lvlsrc : LevelSource ,
414
- span : Option < Span > ,
420
+ span : Option < MultiSpan > ,
415
421
msg : & str )
416
422
-> DiagnosticBuilder < ' a > {
417
423
let ( mut level, source) = lvlsrc;
@@ -442,7 +448,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
442
448
// For purposes of printing, we can treat forbid as deny.
443
449
if level == Forbid { level = Deny ; }
444
450
445
- let mut err = match ( level, span) {
451
+ let mut err = match ( level, span. clone ( ) ) {
446
452
( Warn , Some ( sp) ) => sess. struct_span_warn ( sp, & msg[ ..] ) ,
447
453
( Warn , None ) => sess. struct_warn ( & msg[ ..] ) ,
448
454
( Deny , Some ( sp) ) => sess. struct_span_err ( sp, & msg[ ..] ) ,
@@ -458,7 +464,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
458
464
let citation = format ! ( "for more information, see {}" ,
459
465
future_incompatible. reference) ;
460
466
if let Some ( sp) = span {
461
- err. fileline_warn ( sp, & explanation) ;
467
+ err. fileline_warn ( sp. clone ( ) , & explanation) ;
462
468
err. fileline_note ( sp, & citation) ;
463
469
} else {
464
470
err. warn ( & explanation) ;
@@ -497,31 +503,39 @@ pub trait LintContext: Sized {
497
503
} )
498
504
}
499
505
500
- fn lookup_and_emit ( & self , lint : & ' static Lint , span : Option < Span > , msg : & str ) {
506
+ fn lookup_and_emit < S : Into < MultiSpan > > ( & self ,
507
+ lint : & ' static Lint ,
508
+ span : Option < S > ,
509
+ msg : & str ) {
501
510
let ( level, src) = match self . level_src ( lint) {
502
511
None => return ,
503
512
Some ( pair) => pair,
504
513
} ;
505
514
506
- raw_emit_lint ( & self . sess ( ) , self . lints ( ) , lint, ( level, src) , span, msg) ;
515
+ raw_emit_lint ( & self . sess ( ) , self . lints ( ) , lint, ( level, src) , span. map ( |s| s . into ( ) ) , msg) ;
507
516
}
508
517
509
- fn lookup ( & self ,
510
- lint : & ' static Lint ,
511
- span : Option < Span > ,
512
- msg : & str )
513
- -> DiagnosticBuilder {
518
+ fn lookup < S : Into < MultiSpan > > ( & self ,
519
+ lint : & ' static Lint ,
520
+ span : Option < S > ,
521
+ msg : & str )
522
+ -> DiagnosticBuilder {
514
523
let ( level, src) = match self . level_src ( lint) {
515
524
None => return self . sess ( ) . diagnostic ( ) . struct_dummy ( ) ,
516
525
Some ( pair) => pair,
517
526
} ;
518
527
519
- raw_struct_lint ( & self . sess ( ) , self . lints ( ) , lint, ( level, src) , span, msg)
528
+ raw_struct_lint ( & self . sess ( ) ,
529
+ self . lints ( ) ,
530
+ lint,
531
+ ( level, src) ,
532
+ span. map ( |s| s. into ( ) ) ,
533
+ msg)
520
534
}
521
535
522
536
/// Emit a lint at the appropriate level, for a particular span.
523
- fn span_lint ( & self , lint : & ' static Lint , span : Span , msg : & str ) {
524
- self . lookup_and_emit ( lint, Some ( span) , msg) ;
537
+ fn span_lint < S : Into < MultiSpan > > ( & self , lint : & ' static Lint , span : S , msg : & str ) {
538
+ self . lookup_and_emit ( lint, Some ( span. into ( ) ) , msg) ;
525
539
}
526
540
527
541
fn struct_span_lint ( & self ,
@@ -559,7 +573,7 @@ pub trait LintContext: Sized {
559
573
560
574
/// Emit a lint at the appropriate level, with no associated span.
561
575
fn lint ( & self , lint : & ' static Lint , msg : & str ) {
562
- self . lookup_and_emit ( lint, None , msg) ;
576
+ self . lookup_and_emit ( lint, None :: < MultiSpan > , msg) ;
563
577
}
564
578
565
579
/// Merge the lints specified by any lint attributes into the
@@ -646,6 +660,7 @@ impl<'a> EarlyContext<'a> {
646
660
sess : sess,
647
661
krate : krate,
648
662
lints : lint_store,
663
+ collapsed_lints : vec ! [ ] ,
649
664
level_stack : vec ! [ ] ,
650
665
}
651
666
}
@@ -674,6 +689,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
674
689
krate : krate,
675
690
access_levels : access_levels,
676
691
lints : lint_store,
692
+ collapsed_lints : vec ! [ ] ,
677
693
level_stack : vec ! [ ] ,
678
694
node_levels : RefCell :: new ( FnvHashMap ( ) ) ,
679
695
}
@@ -1069,25 +1085,43 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
1069
1085
// Output any lints that were previously added to the session.
1070
1086
impl < ' a , ' tcx > IdVisitingOperation for LateContext < ' a , ' tcx > {
1071
1087
fn visit_id ( & mut self , id : ast:: NodeId ) {
1072
- match self . sess ( ) . lints . borrow_mut ( ) . remove ( & id) {
1073
- None => { }
1074
- Some ( lints) => {
1075
- debug ! ( "LateContext::visit_id: id={:?} lints={:?}" , id, lints) ;
1076
- for ( lint_id, span, msg) in lints {
1077
- self . span_lint ( lint_id. lint , span, & msg[ ..] )
1088
+ let lints_opt = { self . sess ( ) . lints . borrow_mut ( ) . remove ( & id) } ;
1089
+ if let Some ( lints) = lints_opt {
1090
+ debug ! ( "LateContext::visit_id: id={:?} lints={:?}" , id, lints) ;
1091
+ for ( lint_id, span, msg) in lints {
1092
+ let level_src = match self . level_src ( lint_id. lint ) {
1093
+ None => continue ,
1094
+ Some ( pair) => pair,
1095
+ } ;
1096
+ if let Some ( & mut ( ref p_id, ref p_msg, p_lvlsrc, ref mut group) ) =
1097
+ self . collapsed_lints . last_mut ( ) {
1098
+ if * p_id == lint_id && * p_msg == msg && p_lvlsrc == level_src {
1099
+ group. push ( span) ;
1100
+ continue ;
1101
+ }
1078
1102
}
1103
+ self . collapsed_lints . push ( ( lint_id, msg, level_src, vec ! [ span] ) ) ;
1079
1104
}
1080
1105
}
1081
1106
}
1082
1107
}
1083
1108
impl < ' a > IdVisitingOperation for EarlyContext < ' a > {
1084
1109
fn visit_id ( & mut self , id : ast:: NodeId ) {
1085
- match self . sess . lints . borrow_mut ( ) . remove ( & id) {
1086
- None => { }
1087
- Some ( lints) => {
1088
- for ( lint_id, span, msg) in lints {
1089
- self . span_lint ( lint_id. lint , span, & msg[ ..] )
1110
+ let lints_opt = { self . sess ( ) . lints . borrow_mut ( ) . remove ( & id) } ;
1111
+ if let Some ( lints) = lints_opt {
1112
+ for ( lint_id, span, msg) in lints {
1113
+ let level_src = match self . level_src ( lint_id. lint ) {
1114
+ None => continue ,
1115
+ Some ( pair) => pair,
1116
+ } ;
1117
+ if let Some ( & mut ( ref p_id, ref p_msg, p_lvl_src, ref mut group) ) =
1118
+ self . collapsed_lints . last_mut ( ) {
1119
+ if * p_id == lint_id && * p_msg == msg && p_lvl_src== level_src {
1120
+ group. push ( span) ;
1121
+ continue ;
1122
+ }
1090
1123
}
1124
+ self . collapsed_lints . push ( ( lint_id, msg, level_src, vec ! [ span] ) ) ;
1091
1125
}
1092
1126
}
1093
1127
}
@@ -1255,6 +1289,12 @@ pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
1255
1289
hir_visit:: walk_crate ( cx, krate) ;
1256
1290
} ) ;
1257
1291
1292
+ for ( lint_id, msg, lvl_src, spans) in mem:: replace ( & mut cx. collapsed_lints , Vec :: new ( ) ) {
1293
+ for msp in tcx. sess . codemap ( ) . group_spans ( spans) {
1294
+ raw_emit_lint ( & tcx. sess , cx. lints ( ) , lint_id. lint , lvl_src, Some ( msp) , & msg) ;
1295
+ }
1296
+ }
1297
+
1258
1298
// If we missed any lints added to the session, then there's a bug somewhere
1259
1299
// in the iteration code.
1260
1300
for ( id, v) in tcx. sess . lints . borrow ( ) . iter ( ) {
@@ -1286,6 +1326,12 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
1286
1326
ast_visit:: walk_crate ( cx, krate) ;
1287
1327
} ) ;
1288
1328
1329
+ for ( lint_id, msg, lvl_src, spans) in mem:: replace ( & mut cx. collapsed_lints , Vec :: new ( ) ) {
1330
+ for msp in sess. codemap ( ) . group_spans ( spans) {
1331
+ raw_emit_lint ( sess, cx. lints ( ) , lint_id. lint , lvl_src, Some ( msp) , & msg) ;
1332
+ }
1333
+ }
1334
+
1289
1335
// Put the lint store back in the session.
1290
1336
mem:: replace ( & mut * sess. lint_store . borrow_mut ( ) , cx. lints ) ;
1291
1337
0 commit comments