diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 20463f42d3b1..bcc8384dd0ea 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,6 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; +use std::fmt; use syntax::attr; use syntax::parse::token::InternedString; use syntax::ast; @@ -80,6 +81,41 @@ pub struct LintStore { lint_cap: Option, } +/// When you call `add_lint` on the session, you wind up storing one +/// of these, which records a "potential lint" at a particular point. +pub struct EarlyLint { + /// what lint is this? (e.g., `dead_code`) + pub id: LintId, + + /// the span where the lint will be reported at + pub span: Span, + + /// the main message + pub msg: String, +} + +impl fmt::Debug for EarlyLint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("EarlyLint") + .field("id", &self.id) + .field("span", &self.span) + .field("msg", &self.msg) + .finish() + } +} + +impl EarlyLint { + pub fn new(id: LintId, span: Span, msg: String) -> Self { + EarlyLint { id: id, span: span, msg: msg } + } + + pub fn matches(&self, other: &EarlyLint) -> bool { + self.id == other.id && self.span == other.span && self.msg == other.msg + } +} + + + /// Extra information for a future incompatibility lint. See the call /// to `register_future_incompatible` in `librustc_lint/lib.rs` for /// guidelines. @@ -514,6 +550,11 @@ pub trait LintContext: Sized { self.lookup_and_emit(lint, Some(span), msg); } + fn early_lint(&self, early_lint: EarlyLint) { + let mut err = self.struct_span_lint(early_lint.id.lint, early_lint.span, &early_lint.msg); + err.emit(); + } + fn struct_span_lint(&self, lint: &'static Lint, span: Span, @@ -1065,8 +1106,8 @@ impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { fn visit_id(&mut self, id: ast::NodeId) { if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); - for (lint_id, span, msg) in lints { - self.cx.span_lint(lint_id.lint, span, &msg[..]) + for early_lint in lints { + self.cx.early_lint(early_lint); } } } @@ -1211,10 +1252,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. for (id, v) in tcx.sess.lints.borrow().iter() { - for &(lint, span, ref msg) in v { - span_bug!(span, - "unprocessed lint {} at {}: {}", - lint.to_string(), tcx.map.node_to_string(*id), *msg) + for early_lint in v { + span_bug!(early_lint.span, + "unprocessed lint {:?} at {}", + early_lint, tcx.map.node_to_string(*id)); } } @@ -1229,8 +1270,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { cx.with_lint_attrs(&krate.attrs, |cx| { // Lints may be assigned to the whole crate. if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) { - for (lint_id, span, msg) in lints { - cx.span_lint(lint_id.lint, span, &msg[..]) + for early_lint in lints { + cx.early_lint(early_lint); } } @@ -1249,8 +1290,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. for (_, v) in sess.lints.borrow().iter() { - for &(lint, span, ref msg) in v { - span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg) + for early_lint in v { + span_bug!(early_lint.span, "unprocessed lint {:?}", early_lint); } } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 7eea6a2fcf27..0e11546e643e 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -41,7 +41,7 @@ use hir; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, raw_emit_lint, check_crate, check_ast_crate, gather_attrs, - raw_struct_lint, FutureIncompatibleInfo}; + raw_struct_lint, FutureIncompatibleInfo, EarlyLint}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1ce5b223fbef..acfdfc9a0271 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -74,7 +74,7 @@ pub struct Session { pub local_crate_source_file: Option, pub working_dir: PathBuf, pub lint_store: RefCell, - pub lints: RefCell>>, + pub lints: RefCell>>, /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics /// that have been set once, but should not be set again, in order to avoid /// redundantly verbose output (Issue #24690). @@ -265,14 +265,14 @@ impl Session { msg: String) { let lint_id = lint::LintId::of(lint); let mut lints = self.lints.borrow_mut(); + let early_lint = lint::EarlyLint::new(lint_id, sp, msg); if let Some(arr) = lints.get_mut(&id) { - let tuple = (lint_id, sp, msg); - if !arr.contains(&tuple) { - arr.push(tuple); + if !arr.iter().any(|l| l.matches(&early_lint)) { + arr.push(early_lint); } return; } - lints.insert(id, vec![(lint_id, sp, msg)]); + lints.insert(id, vec![early_lint]); } pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId { let id = self.next_node_id.get();