Rework how diagnostic lints are stored.
`Diagnostic::code` has the type `DiagnosticId`, which has `Error` and `Lint` variants. Plus `Diagnostic::is_lint` is a bool, which should be redundant w.r.t. `Diagnostic::code`. Seems simple. Except it's possible for a lint to have an error code, in which case its `code` field is recorded as `Error`, and `is_lint` is required to indicate that it's a lint. This is what happens with `derive(LintDiagnostic)` lints. Which means those lints don't have a lint name or a `has_future_breakage` field because those are stored in the `DiagnosticId::Lint`. It's all a bit messy and confused and seems unintentional. This commit: - removes `DiagnosticId`; - changes `Diagnostic::code` to `Option<String>`, which means both errors and lints can straightforwardly have an error code; - changes `Diagnostic::is_lint` to `Option<IsLint>`, where `IsLint` is a new type containing a lint name and a `has_future_breakage` bool, so all lints can have those, error code or not.
This commit is contained in:
parent
2de99ec787
commit
d71f535a6f
24 changed files with 110 additions and 130 deletions
|
@ -9,8 +9,8 @@ use crate::emitter::FileWithAnnotatedLines;
|
|||
use crate::snippet::Line;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::{
|
||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
||||
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
||||
CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, FluentBundle, LazyFallbackBundle,
|
||||
Level, MultiSpan, Style, SubDiagnostic,
|
||||
};
|
||||
use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
@ -127,7 +127,7 @@ impl AnnotateSnippetEmitter {
|
|||
level: &Level,
|
||||
messages: &[(DiagnosticMessage, Style)],
|
||||
args: &FluentArgs<'_>,
|
||||
code: &Option<DiagnosticId>,
|
||||
code: &Option<String>,
|
||||
msp: &MultiSpan,
|
||||
_children: &[SubDiagnostic],
|
||||
_suggestions: &[CodeSuggestion],
|
||||
|
@ -181,11 +181,7 @@ impl AnnotateSnippetEmitter {
|
|||
let snippet = Snippet {
|
||||
title: Some(Annotation {
|
||||
label: Some(&message),
|
||||
id: code.as_ref().map(|c| match c {
|
||||
DiagnosticId::Error(val) | DiagnosticId::Lint { name: val, .. } => {
|
||||
val.as_str()
|
||||
}
|
||||
}),
|
||||
id: code.as_deref(),
|
||||
annotation_type: annotation_type_for_level(*level),
|
||||
}),
|
||||
footer: vec![],
|
||||
|
|
|
@ -104,7 +104,7 @@ pub struct Diagnostic {
|
|||
pub(crate) level: Level,
|
||||
|
||||
pub messages: Vec<(DiagnosticMessage, Style)>,
|
||||
pub code: Option<DiagnosticId>,
|
||||
pub code: Option<String>,
|
||||
pub span: MultiSpan,
|
||||
pub children: Vec<SubDiagnostic>,
|
||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||
|
@ -115,9 +115,9 @@ pub struct Diagnostic {
|
|||
/// `span` if there is one. Otherwise, it is `DUMMY_SP`.
|
||||
pub sort_span: Span,
|
||||
|
||||
/// If diagnostic is from Lint, custom hash function ignores notes
|
||||
/// otherwise hash is based on the all the fields
|
||||
pub is_lint: bool,
|
||||
/// If diagnostic is from Lint, custom hash function ignores children.
|
||||
/// Otherwise hash is based on the all the fields.
|
||||
pub is_lint: Option<IsLint>,
|
||||
|
||||
/// With `-Ztrack_diagnostics` enabled,
|
||||
/// we print where in rustc this error was emitted.
|
||||
|
@ -146,13 +146,11 @@ impl fmt::Display for DiagnosticLocation {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum DiagnosticId {
|
||||
Error(String),
|
||||
Lint {
|
||||
name: String,
|
||||
/// Indicates whether this lint should show up in cargo's future breakage report.
|
||||
has_future_breakage: bool,
|
||||
},
|
||||
pub struct IsLint {
|
||||
/// The lint name.
|
||||
pub(crate) name: String,
|
||||
/// Indicates whether this lint should show up in cargo's future breakage report.
|
||||
has_future_breakage: bool,
|
||||
}
|
||||
|
||||
/// A "sub"-diagnostic attached to a parent diagnostic.
|
||||
|
@ -231,7 +229,7 @@ impl Diagnostic {
|
|||
suggestions: Ok(vec![]),
|
||||
args: Default::default(),
|
||||
sort_span: DUMMY_SP,
|
||||
is_lint: false,
|
||||
is_lint: None,
|
||||
emitted_at: DiagnosticLocation::caller(),
|
||||
}
|
||||
}
|
||||
|
@ -288,16 +286,13 @@ impl Diagnostic {
|
|||
|
||||
/// Indicates whether this diagnostic should show up in cargo's future breakage report.
|
||||
pub(crate) fn has_future_breakage(&self) -> bool {
|
||||
match self.code {
|
||||
Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))
|
||||
}
|
||||
|
||||
pub(crate) fn is_force_warn(&self) -> bool {
|
||||
match self.level {
|
||||
Level::ForceWarning(_) => {
|
||||
assert!(self.is_lint);
|
||||
assert!(self.is_lint.is_some());
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
|
@ -893,12 +888,12 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn is_lint(&mut self) -> &mut Self {
|
||||
self.is_lint = true;
|
||||
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
|
||||
self.is_lint = Some(IsLint { name, has_future_breakage });
|
||||
self
|
||||
}
|
||||
|
||||
pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
|
||||
pub fn code(&mut self, s: String) -> &mut Self {
|
||||
self.code = Some(s);
|
||||
self
|
||||
}
|
||||
|
@ -908,8 +903,8 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn get_code(&self) -> Option<DiagnosticId> {
|
||||
self.code.clone()
|
||||
pub fn get_code(&self) -> Option<&str> {
|
||||
self.code.as_deref()
|
||||
}
|
||||
|
||||
pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
|
@ -995,7 +990,8 @@ impl Diagnostic {
|
|||
&Level,
|
||||
&[(DiagnosticMessage, Style)],
|
||||
Vec<(&Cow<'static, str>, &DiagnosticArgValue<'static>)>,
|
||||
&Option<DiagnosticId>,
|
||||
&Option<String>,
|
||||
&Option<IsLint>,
|
||||
&MultiSpan,
|
||||
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||
Option<&[SubDiagnostic]>,
|
||||
|
@ -1005,9 +1001,10 @@ impl Diagnostic {
|
|||
&self.messages,
|
||||
self.args().collect(),
|
||||
&self.code,
|
||||
&self.is_lint,
|
||||
&self.span,
|
||||
&self.suggestions,
|
||||
(if self.is_lint { None } else { Some(&self.children) }),
|
||||
(if self.is_lint.is_some() { None } else { Some(&self.children) }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::diagnostic::IntoDiagnosticArg;
|
||||
use crate::{DiagCtxt, Level, MultiSpan, StashKey};
|
||||
use crate::{
|
||||
Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
|
||||
ExplicitBug, SubdiagnosticMessage,
|
||||
Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, ExplicitBug,
|
||||
SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_lint_defs::Applicability;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
@ -395,8 +395,11 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||
forward!((span, with_span)(
|
||||
sp: impl Into<MultiSpan>,
|
||||
));
|
||||
forward!((is_lint, with_is_lint)(
|
||||
name: String, has_future_breakage: bool,
|
||||
));
|
||||
forward!((code, with_code)(
|
||||
s: DiagnosticId,
|
||||
s: String,
|
||||
));
|
||||
forward!((arg, with_arg)(
|
||||
name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg,
|
||||
|
@ -443,5 +446,5 @@ macro_rules! struct_span_code_err {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! error_code {
|
||||
($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
|
||||
($code:ident) => {{ stringify!($code).to_owned() }};
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ use crate::snippet::{
|
|||
use crate::styled_buffer::StyledBuffer;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::{
|
||||
diagnostic::DiagnosticLocation, CodeSuggestion, DiagCtxt, Diagnostic, DiagnosticId,
|
||||
DiagnosticMessage, FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
|
||||
SubstitutionHighlight, SuggestionStyle, TerminalUrl,
|
||||
diagnostic::DiagnosticLocation, CodeSuggestion, DiagCtxt, Diagnostic, DiagnosticMessage,
|
||||
FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight,
|
||||
SuggestionStyle, TerminalUrl,
|
||||
};
|
||||
use rustc_lint_defs::pluralize;
|
||||
|
||||
|
@ -1309,7 +1309,7 @@ impl HumanEmitter {
|
|||
msp: &MultiSpan,
|
||||
msgs: &[(DiagnosticMessage, Style)],
|
||||
args: &FluentArgs<'_>,
|
||||
code: &Option<DiagnosticId>,
|
||||
code: &Option<String>,
|
||||
level: &Level,
|
||||
max_line_num_len: usize,
|
||||
is_secondary: bool,
|
||||
|
@ -1336,14 +1336,13 @@ impl HumanEmitter {
|
|||
buffer.append(0, level.to_str(), Style::Level(*level));
|
||||
label_width += level.to_str().len();
|
||||
}
|
||||
// only render error codes, not lint codes
|
||||
if let Some(DiagnosticId::Error(ref code)) = *code {
|
||||
if let Some(code) = code {
|
||||
buffer.append(0, "[", Style::Level(*level));
|
||||
let code = if let TerminalUrl::Yes = self.terminal_url {
|
||||
let path = "https://doc.rust-lang.org/error_codes";
|
||||
format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07")
|
||||
Cow::Owned(format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07"))
|
||||
} else {
|
||||
code.clone()
|
||||
Cow::Borrowed(code)
|
||||
};
|
||||
buffer.append(0, &code, Style::Level(*level));
|
||||
buffer.append(0, "]", Style::Level(*level));
|
||||
|
@ -2077,7 +2076,7 @@ impl HumanEmitter {
|
|||
level: &Level,
|
||||
messages: &[(DiagnosticMessage, Style)],
|
||||
args: &FluentArgs<'_>,
|
||||
code: &Option<DiagnosticId>,
|
||||
code: &Option<String>,
|
||||
span: &MultiSpan,
|
||||
children: &[SubDiagnostic],
|
||||
suggestions: &[CodeSuggestion],
|
||||
|
|
|
@ -15,10 +15,9 @@ use termcolor::{ColorSpec, WriteColor};
|
|||
use crate::emitter::{should_show_source_code, Emitter, HumanReadableErrorType};
|
||||
use crate::registry::Registry;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::DiagnosticId;
|
||||
use crate::{
|
||||
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
||||
TerminalUrl,
|
||||
diagnostic::IsLint, CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel,
|
||||
SubDiagnostic, TerminalUrl,
|
||||
};
|
||||
use rustc_lint_defs::Applicability;
|
||||
|
||||
|
@ -301,7 +300,8 @@ struct DiagnosticSpanMacroExpansion {
|
|||
|
||||
#[derive(Serialize)]
|
||||
struct DiagnosticCode {
|
||||
/// The code itself.
|
||||
/// The error code (e.g. "E1234"), if the diagnostic has one. Or the lint
|
||||
/// name, if it's a lint without an error code.
|
||||
code: String,
|
||||
/// An explanation for the code.
|
||||
explanation: Option<&'static str>,
|
||||
|
@ -399,9 +399,21 @@ impl Diagnostic {
|
|||
let output = String::from_utf8(output).unwrap();
|
||||
|
||||
let translated_message = je.translate_messages(&diag.messages, &args);
|
||||
|
||||
let code = if let Some(code) = &diag.code {
|
||||
Some(DiagnosticCode {
|
||||
code: code.to_string(),
|
||||
explanation: je.registry.as_ref().unwrap().try_find_description(&code).ok(),
|
||||
})
|
||||
} else if let Some(IsLint { name, .. }) = &diag.is_lint {
|
||||
Some(DiagnosticCode { code: name.to_string(), explanation: None })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Diagnostic {
|
||||
message: translated_message.to_string(),
|
||||
code: DiagnosticCode::map_opt_string(diag.code.clone(), je),
|
||||
code,
|
||||
level: diag.level.to_str(),
|
||||
spans: DiagnosticSpan::from_multispan(&diag.span, &args, je),
|
||||
children: diag
|
||||
|
@ -592,18 +604,3 @@ impl DiagnosticSpanLine {
|
|||
.unwrap_or_else(|_| vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticCode {
|
||||
fn map_opt_string(s: Option<DiagnosticId>, je: &JsonEmitter) -> Option<DiagnosticCode> {
|
||||
s.map(|s| {
|
||||
let s = match s {
|
||||
DiagnosticId::Error(s) => s,
|
||||
DiagnosticId::Lint { name, .. } => name,
|
||||
};
|
||||
let je_result =
|
||||
je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap();
|
||||
|
||||
DiagnosticCode { code: s, explanation: je_result.ok() }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ extern crate tracing;
|
|||
extern crate self as rustc_errors;
|
||||
|
||||
pub use diagnostic::{
|
||||
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
|
||||
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue,
|
||||
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
|
||||
};
|
||||
pub use diagnostic_builder::{
|
||||
|
@ -442,13 +442,13 @@ struct DiagCtxtInner {
|
|||
/// This is used for the `good_path_delayed_bugs` check.
|
||||
suppressed_expected_diag: bool,
|
||||
|
||||
/// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
|
||||
/// This set contains the code of all emitted diagnostics to avoid
|
||||
/// emitting the same diagnostic with extended help (`--teach`) twice, which
|
||||
/// would be unnecessary repetition.
|
||||
taught_diagnostics: FxHashSet<DiagnosticId>,
|
||||
taught_diagnostics: FxHashSet<String>,
|
||||
|
||||
/// Used to suggest rustc --explain `<error code>`
|
||||
emitted_diagnostic_codes: FxIndexSet<DiagnosticId>,
|
||||
emitted_diagnostic_codes: FxIndexSet<String>,
|
||||
|
||||
/// This set contains a hash of every diagnostic that has been emitted by
|
||||
/// this `DiagCtxt`. These hashes is used to avoid emitting the same error
|
||||
|
@ -676,7 +676,7 @@ impl DiagCtxt {
|
|||
let key = (span.with_parent(None), key);
|
||||
|
||||
if diag.is_error() {
|
||||
if diag.is_lint {
|
||||
if diag.is_lint.is_some() {
|
||||
inner.lint_err_count += 1;
|
||||
} else {
|
||||
inner.err_count += 1;
|
||||
|
@ -695,7 +695,7 @@ impl DiagCtxt {
|
|||
let key = (span.with_parent(None), key);
|
||||
let diag = inner.stashed_diagnostics.remove(&key)?;
|
||||
if diag.is_error() {
|
||||
if diag.is_lint {
|
||||
if diag.is_lint.is_some() {
|
||||
inner.lint_err_count -= 1;
|
||||
} else {
|
||||
inner.err_count -= 1;
|
||||
|
@ -715,9 +715,7 @@ impl DiagCtxt {
|
|||
|
||||
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
|
||||
///
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
/// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_warn(
|
||||
|
@ -730,9 +728,7 @@ impl DiagCtxt {
|
|||
|
||||
/// Construct a builder at the `Warning` level with the `msg`.
|
||||
///
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
/// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
|
@ -1011,11 +1007,12 @@ impl DiagCtxt {
|
|||
let mut error_codes = inner
|
||||
.emitted_diagnostic_codes
|
||||
.iter()
|
||||
.filter_map(|x| match &x {
|
||||
DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
|
||||
Some(s.clone())
|
||||
.filter_map(|code| {
|
||||
if registry.try_find_description(code).is_ok().clone() {
|
||||
Some(code.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !error_codes.is_empty() {
|
||||
|
@ -1058,8 +1055,8 @@ impl DiagCtxt {
|
|||
///
|
||||
/// Used to suppress emitting the same error multiple times with extended explanation when
|
||||
/// calling `-Zteach`.
|
||||
pub fn must_teach(&self, code: &DiagnosticId) -> bool {
|
||||
self.inner.borrow_mut().taught_diagnostics.insert(code.clone())
|
||||
pub fn must_teach(&self, code: &str) -> bool {
|
||||
self.inner.borrow_mut().taught_diagnostics.insert(code.to_string())
|
||||
}
|
||||
|
||||
pub fn force_print_diagnostic(&self, db: Diagnostic) {
|
||||
|
@ -1231,7 +1228,7 @@ impl DiagCtxtInner {
|
|||
for diag in diags {
|
||||
// Decrement the count tracking the stash; emitting will increment it.
|
||||
if diag.is_error() {
|
||||
if diag.is_lint {
|
||||
if diag.is_lint.is_some() {
|
||||
self.lint_err_count -= 1;
|
||||
} else {
|
||||
self.err_count -= 1;
|
||||
|
@ -1363,7 +1360,7 @@ impl DiagCtxtInner {
|
|||
self.has_printed = true;
|
||||
}
|
||||
if diagnostic.is_error() {
|
||||
if diagnostic.is_lint {
|
||||
if diagnostic.is_lint.is_some() {
|
||||
self.lint_err_count += 1;
|
||||
} else {
|
||||
self.err_count += 1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue