Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introing one-time diagnostics: only emit "lint level defined here" once #37191

Merged
merged 4 commits into from
Oct 31, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session,
}

if let Some(span) = def {
let explanation = "lint level defined here";
err.span_note(span, &explanation);
sess.diag_span_note_once(&mut err, span, "lint level defined here");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. So the key is the span+message, but it's possible that the level for many lints is set at one point (e.g., #[allow(warnings)]). Do we want to issue one note per kind of lint, or just one per span? I'm actually not sure =)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm leaning towards one-per-lint (ef6a072).

}

err
Expand Down
27 changes: 26 additions & 1 deletion src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use middle::dependency_format;
use session::search_paths::PathKind;
use session::config::DebugInfoLevel;
use ty::tls;
use util::nodemap::{NodeMap, FnvHashMap};
use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
use util::common::duration_to_secs_str;
use mir::transform as mir_pass;

Expand Down Expand Up @@ -75,6 +75,10 @@ pub struct Session {
pub working_dir: PathBuf,
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
/// Set of (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).
pub one_time_diagnostics: RefCell<FnvHashSet<(Span, String)>>,
pub plugin_llvm_passes: RefCell<Vec<String>>,
pub mir_passes: RefCell<mir_pass::Passes>,
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
Expand Down Expand Up @@ -288,6 +292,26 @@ impl Session {
pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
&self.parse_sess.span_diagnostic
}

/// Analogous to calling `.span_note` on the given DiagnosticBuilder, but
/// deduplicates on span and message for this `Session`.
//
// FIXME: if the need arises for one-time diagnostics other than
// `span_note`, we almost certainly want to generalize this "check the
// one-time diagnostics map, then set message if it's not already there"
// code to accomodate all of them
pub fn diag_span_note_once<'a, 'b>(&'a self,
diag_builder: &'b mut DiagnosticBuilder<'a>,
span: Span, message: &str) {
let span_message = (span, message.to_owned());
let already_noted: bool = self.one_time_diagnostics.borrow()
.contains(&span_message);
if !already_noted {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: you can write

let fresh = self.one_time_diagnostics.borrow_mut().insert(&span_message);
if fresh {
    diag_builder.span_note(span, &message);
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diag_builder.span_note(span, &message);
self.one_time_diagnostics.borrow_mut().insert(span_message);
}
}

pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
self.parse_sess.codemap()
}
Expand Down Expand Up @@ -561,6 +585,7 @@ pub fn build_session_(sopts: config::Options,
working_dir: env::current_dir().unwrap(),
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(NodeMap()),
one_time_diagnostics: RefCell::new(FnvHashSet()),
plugin_llvm_passes: RefCell::new(Vec::new()),
mir_passes: RefCell::new(mir_pass::Passes::new()),
plugin_attributes: RefCell::new(Vec::new()),
Expand Down
2 changes: 0 additions & 2 deletions src/test/compile-fail/lint-group-style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ mod test {

#[forbid(bad_style)]
//~^ NOTE lint level defined here
//~^^ NOTE lint level defined here
mod bad {
fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name

Expand All @@ -30,7 +29,6 @@ mod test {
mod warn {
#![warn(bad_style)]
//~^ NOTE lint level defined here
//~| NOTE lint level defined here

fn CamelCase() {} //~ WARN function `CamelCase` should have a snake case name

Expand Down
14 changes: 1 addition & 13 deletions src/test/compile-fail/lint-unconditional-recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,7 @@

#![deny(unconditional_recursion)]
//~^ NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here
//~| NOTE lint level defined here

#![allow(dead_code)]
fn foo() { //~ ERROR function cannot return without recurring
foo(); //~ NOTE recursive call site
Expand Down