introduce EarlyLint type

For now, this type just replaces a tuple, but it will eventually grow
the ability to carry more structured information.
This commit is contained in:
Niko Matsakis 2016-10-06 04:56:13 -04:00
parent bd5fa7532d
commit 75bc8bfa92
3 changed files with 57 additions and 16 deletions

View file

@ -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<Level>,
}
/// 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);
}
}
}

View file

@ -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)]

View file

@ -74,7 +74,7 @@ pub struct Session {
pub local_crate_source_file: Option<PathBuf>,
pub working_dir: PathBuf,
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
pub lints: RefCell<NodeMap<Vec<lint::EarlyLint>>>,
/// 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();