Rollup merge of #145747 - joshtriplett:builtin-diag-dyn, r=jdonszelmann
Refactor lint buffering to avoid requiring a giant enum Lint buffering currently relies on a giant enum `BuiltinLintDiag` containing all the lints that might potentially get buffered. In addition to being an unwieldy enum in a central crate, this also makes `rustc_lint_defs` a build bottleneck: it depends on various types from various crates (with a steady pressure to add more), and many crates depend on it. Having all of these variants in a separate crate also prevents detecting when a variant becomes unused, which we can do with a dedicated type defined and used in the same crate. Refactor this to use a dyn trait, to allow using `LintDiagnostic` types directly. Because the existing `BuiltinLintDiag` requires some additional types in order to decorate some variants, which are only available later in `rustc_lint`, use an enum `DecorateDiagCompat` to handle both the `dyn LintDiagnostic` case and the `BuiltinLintDiag` case. --- With the infrastructure in place, use it to migrate three of the enum variants to use `LintDiagnostic` directly, as a proof of concept and to demonstrate that the net result is a reduction in code size and a removal of a boilerplate-heavy layer of indirection. Also remove an unused `BuiltinLintDiag` variant.
This commit is contained in:
@@ -8,8 +8,9 @@ use rustc_ast::{Path, Visibility};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic,
|
||||
SuggestionStyle,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
@@ -3601,3 +3602,76 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(parse_hidden_unicode_codepoints)]
|
||||
#[note]
|
||||
pub(crate) struct HiddenUnicodeCodepointsDiag {
|
||||
pub label: String,
|
||||
pub count: usize,
|
||||
#[label]
|
||||
pub span_label: Span,
|
||||
#[subdiagnostic]
|
||||
pub labels: Option<HiddenUnicodeCodepointsDiagLabels>,
|
||||
#[subdiagnostic]
|
||||
pub sub: HiddenUnicodeCodepointsDiagSub,
|
||||
}
|
||||
|
||||
pub(crate) struct HiddenUnicodeCodepointsDiagLabels {
|
||||
pub spans: Vec<(char, Span)>,
|
||||
}
|
||||
|
||||
impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
for (c, span) in self.spans {
|
||||
diag.span_label(span, format!("{c:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum HiddenUnicodeCodepointsDiagSub {
|
||||
Escape { spans: Vec<(char, Span)> },
|
||||
NoEscape { spans: Vec<(char, Span)> },
|
||||
}
|
||||
|
||||
// Used because of multiple multipart_suggestion and note
|
||||
impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
match self {
|
||||
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
|
||||
diag.multipart_suggestion_with_style(
|
||||
fluent::parse_suggestion_remove,
|
||||
spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
diag.multipart_suggestion(
|
||||
fluent::parse_suggestion_escape,
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, span)| {
|
||||
let c = format!("{c:?}");
|
||||
(span, c[1..c.len() - 1].to_string())
|
||||
})
|
||||
.collect(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => {
|
||||
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We
|
||||
// should do the same here to provide the same good suggestions as we do for
|
||||
// literals above.
|
||||
diag.arg(
|
||||
"escaped",
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, _)| format!("{c:?}"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
);
|
||||
diag.note(fluent::parse_suggestion_remove);
|
||||
diag.note(fluent::parse_no_suggestion_note_escape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,21 +543,21 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let label = label.to_string();
|
||||
let count = spans.len();
|
||||
let labels = point_at_inner_spans.then_some(spans.clone());
|
||||
let labels = point_at_inner_spans
|
||||
.then_some(errors::HiddenUnicodeCodepointsDiagLabels { spans: spans.clone() });
|
||||
let sub = if point_at_inner_spans && !spans.is_empty() {
|
||||
errors::HiddenUnicodeCodepointsDiagSub::Escape { spans }
|
||||
} else {
|
||||
errors::HiddenUnicodeCodepointsDiagSub::NoEscape { spans }
|
||||
};
|
||||
|
||||
self.psess.buffer_lint(
|
||||
TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::HiddenUnicodeCodepoints {
|
||||
label: label.to_string(),
|
||||
count,
|
||||
span_label: span,
|
||||
labels,
|
||||
escape: point_at_inner_spans && !spans.is_empty(),
|
||||
spans,
|
||||
},
|
||||
errors::HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub },
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user