Skip to content

Commit 2154eb7

Browse files
committed
Collapse built-in lint reporting
Fold consecutive lint reports which only differ in span together.
1 parent ddd1bf5 commit 2154eb7

File tree

4 files changed

+77
-31
lines changed

4 files changed

+77
-31
lines changed

src/librustc/lint/context.rs

+73-27
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use std::default::Default as StdDefault;
4141
use std::mem;
4242
use syntax::ast_util::{self, IdVisitingOperation};
4343
use syntax::attr::{self, AttrMetaMethods};
44-
use syntax::codemap::Span;
44+
use syntax::codemap::{Span, MultiSpan};
4545
use syntax::errors::DiagnosticBuilder;
4646
use syntax::parse::token::InternedString;
4747
use syntax::ast;
@@ -309,6 +309,9 @@ pub struct LateContext<'a, 'tcx: 'a> {
309309
/// The store of registered lints.
310310
lints: LintStore,
311311

312+
/// Sink to collect and fold consecutive lints together
313+
collapsed_lints: Vec<(LintId, String, LevelSource, Vec<Span>)>,
314+
312315
/// When recursing into an attributed node of the ast which modifies lint
313316
/// levels, this stack keeps track of the previous lint levels of whatever
314317
/// was modified.
@@ -331,6 +334,9 @@ pub struct EarlyContext<'a> {
331334
/// The store of registered lints.
332335
lints: LintStore,
333336

337+
/// Sink to collect and fold consecutive lints together
338+
collapsed_lints: Vec<(LintId, String, LevelSource, Vec<Span>)>,
339+
334340
/// When recursing into an attributed node of the ast which modifies lint
335341
/// levels, this stack keeps track of the previous lint levels of whatever
336342
/// was modified.
@@ -402,7 +408,7 @@ pub fn raw_emit_lint(sess: &Session,
402408
lints: &LintStore,
403409
lint: &'static Lint,
404410
lvlsrc: LevelSource,
405-
span: Option<Span>,
411+
span: Option<MultiSpan>,
406412
msg: &str) {
407413
raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
408414
}
@@ -411,7 +417,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
411417
lints: &LintStore,
412418
lint: &'static Lint,
413419
lvlsrc: LevelSource,
414-
span: Option<Span>,
420+
span: Option<MultiSpan>,
415421
msg: &str)
416422
-> DiagnosticBuilder<'a> {
417423
let (mut level, source) = lvlsrc;
@@ -442,7 +448,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
442448
// For purposes of printing, we can treat forbid as deny.
443449
if level == Forbid { level = Deny; }
444450

445-
let mut err = match (level, span) {
451+
let mut err = match (level, span.clone()) {
446452
(Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
447453
(Warn, None) => sess.struct_warn(&msg[..]),
448454
(Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
@@ -458,7 +464,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
458464
let citation = format!("for more information, see {}",
459465
future_incompatible.reference);
460466
if let Some(sp) = span {
461-
err.fileline_warn(sp, &explanation);
467+
err.fileline_warn(sp.clone(), &explanation);
462468
err.fileline_note(sp, &citation);
463469
} else {
464470
err.warn(&explanation);
@@ -497,31 +503,39 @@ pub trait LintContext: Sized {
497503
})
498504
}
499505

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) {
501510
let (level, src) = match self.level_src(lint) {
502511
None => return,
503512
Some(pair) => pair,
504513
};
505514

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);
507516
}
508517

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 {
514523
let (level, src) = match self.level_src(lint) {
515524
None => return self.sess().diagnostic().struct_dummy(),
516525
Some(pair) => pair,
517526
};
518527

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)
520534
}
521535

522536
/// 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);
525539
}
526540

527541
fn struct_span_lint(&self,
@@ -559,7 +573,7 @@ pub trait LintContext: Sized {
559573

560574
/// Emit a lint at the appropriate level, with no associated span.
561575
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);
563577
}
564578

565579
/// Merge the lints specified by any lint attributes into the
@@ -646,6 +660,7 @@ impl<'a> EarlyContext<'a> {
646660
sess: sess,
647661
krate: krate,
648662
lints: lint_store,
663+
collapsed_lints: vec![],
649664
level_stack: vec![],
650665
}
651666
}
@@ -674,6 +689,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
674689
krate: krate,
675690
access_levels: access_levels,
676691
lints: lint_store,
692+
collapsed_lints: vec![],
677693
level_stack: vec![],
678694
node_levels: RefCell::new(FnvHashMap()),
679695
}
@@ -1069,25 +1085,43 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
10691085
// Output any lints that were previously added to the session.
10701086
impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
10711087
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+
}
10781102
}
1103+
self.collapsed_lints.push((lint_id, msg, level_src, vec![span]));
10791104
}
10801105
}
10811106
}
10821107
}
10831108
impl<'a> IdVisitingOperation for EarlyContext<'a> {
10841109
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+
}
10901123
}
1124+
self.collapsed_lints.push((lint_id, msg, level_src, vec![span]));
10911125
}
10921126
}
10931127
}
@@ -1255,6 +1289,12 @@ pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
12551289
hir_visit::walk_crate(cx, krate);
12561290
});
12571291

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+
12581298
// If we missed any lints added to the session, then there's a bug somewhere
12591299
// in the iteration code.
12601300
for (id, v) in tcx.sess.lints.borrow().iter() {
@@ -1286,6 +1326,12 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
12861326
ast_visit::walk_crate(cx, krate);
12871327
});
12881328

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+
12891335
// Put the lint store back in the session.
12901336
mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);
12911337

src/librustc/lint/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
4444
raw_struct_lint, GatherNodeLevels, FutureIncompatibleInfo};
4545

4646
/// Specification of a single lint.
47-
#[derive(Copy, Clone, Debug)]
47+
#[derive(Copy, Clone, Debug, PartialEq)]
4848
pub struct Lint {
4949
/// A string identifier for the lint.
5050
///

src/librustc_resolve/check_unused.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
6767
self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
6868
id,
6969
span,
70-
"unused import".to_string());
70+
"unused import(s)".to_string());
7171
}
7272

7373
let mut def_map = self.def_map.borrow_mut();
@@ -150,7 +150,7 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
150150
.add_lint(lint::builtin::UNUSED_IMPORTS,
151151
item.id,
152152
p.span,
153-
"unused import".to_string());
153+
"unused import(s)".to_string());
154154
}
155155
}
156156
}

src/librustc_trans/trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2368,7 +2368,7 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span,
23682368
&ccx.tcx().sess.lint_store.borrow(),
23692369
lint::builtin::VARIANT_SIZE_DIFFERENCES,
23702370
*lvlsrc.unwrap(),
2371-
Some(sp),
2371+
Some(sp.into()),
23722372
&format!("enum variant is more than three times larger ({} bytes) \
23732373
than the next largest (ignoring padding)",
23742374
largest))

0 commit comments

Comments
 (0)