mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Remove LintDiagnostic derive proc-macro
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
use quote::quote;
|
||||
use synstructure::Structure;
|
||||
|
||||
use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
|
||||
use crate::diagnostics::diagnostic_builder::each_variant;
|
||||
use crate::diagnostics::error::DiagnosticDeriveError;
|
||||
|
||||
/// The central struct for constructing the `into_diag` method from an annotated struct.
|
||||
@@ -19,8 +19,7 @@ pub(crate) fn new(structure: Structure<'a>) -> Self {
|
||||
|
||||
pub(crate) fn into_tokens(self) -> TokenStream {
|
||||
let DiagnosticDerive { mut structure } = self;
|
||||
let kind = DiagnosticDeriveKind::Diagnostic;
|
||||
let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
|
||||
let implementation = each_variant(&mut structure, |mut builder, variant| {
|
||||
let preamble = builder.preamble(variant);
|
||||
let body = builder.body(variant);
|
||||
|
||||
@@ -64,52 +63,3 @@ fn into_diag(
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The central struct for constructing the `decorate_lint` method from an annotated struct.
|
||||
pub(crate) struct LintDiagnosticDerive<'a> {
|
||||
structure: Structure<'a>,
|
||||
}
|
||||
|
||||
impl<'a> LintDiagnosticDerive<'a> {
|
||||
pub(crate) fn new(structure: Structure<'a>) -> Self {
|
||||
Self { structure }
|
||||
}
|
||||
|
||||
pub(crate) fn into_tokens(self) -> TokenStream {
|
||||
let LintDiagnosticDerive { mut structure } = self;
|
||||
let kind = DiagnosticDeriveKind::LintDiagnostic;
|
||||
let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
|
||||
let preamble = builder.preamble(variant);
|
||||
let body = builder.body(variant);
|
||||
|
||||
let Some(message) = builder.primary_message() else {
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
};
|
||||
let message = message.diag_message(Some(variant));
|
||||
let primary_message = quote! {
|
||||
diag.primary_message(#message);
|
||||
};
|
||||
|
||||
let formatting_init = &builder.formatting_init;
|
||||
quote! {
|
||||
#primary_message
|
||||
#preamble
|
||||
#formatting_init
|
||||
#body
|
||||
diag
|
||||
}
|
||||
});
|
||||
|
||||
structure.gen_impl(quote! {
|
||||
gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self {
|
||||
#[track_caller]
|
||||
fn decorate_lint<'__b>(
|
||||
self,
|
||||
diag: &'__b mut rustc_errors::Diag<'__a, ()>
|
||||
) {
|
||||
#implementation;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,54 @@
|
||||
should_generate_arg, type_is_bool, type_is_unit, type_matches_path,
|
||||
};
|
||||
|
||||
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum DiagnosticDeriveKind {
|
||||
Diagnostic,
|
||||
LintDiagnostic,
|
||||
pub(crate) fn each_variant<'s, F>(structure: &mut Structure<'s>, f: F) -> TokenStream
|
||||
where
|
||||
F: for<'v> Fn(DiagnosticDeriveVariantBuilder, &VariantInfo<'v>) -> TokenStream,
|
||||
{
|
||||
let ast = structure.ast();
|
||||
let span = ast.span().unwrap();
|
||||
match ast.data {
|
||||
syn::Data::Struct(..) | syn::Data::Enum(..) => (),
|
||||
syn::Data::Union(..) => {
|
||||
span_err(span, "diagnostic derives can only be used on structs and enums").emit();
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(ast.data, syn::Data::Enum(..)) {
|
||||
for attr in &ast.attrs {
|
||||
span_err(attr.span().unwrap(), "unsupported type attribute for diagnostic derive enum")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
structure.bind_with(|_| synstructure::BindStyle::Move);
|
||||
let variants = structure.each_variant(|variant| {
|
||||
let span = match structure.ast().data {
|
||||
syn::Data::Struct(..) => span,
|
||||
// There isn't a good way to get the span of the variant, so the variant's
|
||||
// name will need to do.
|
||||
_ => variant.ast().ident.span().unwrap(),
|
||||
};
|
||||
let builder = DiagnosticDeriveVariantBuilder {
|
||||
span,
|
||||
field_map: build_field_mapping(variant),
|
||||
formatting_init: TokenStream::new(),
|
||||
message: None,
|
||||
code: None,
|
||||
};
|
||||
f(builder, variant)
|
||||
});
|
||||
|
||||
quote! {
|
||||
match self {
|
||||
#variants
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks persistent information required for a specific variant when building up individual calls
|
||||
/// to diagnostic methods for generated diagnostic derives - both `Diagnostic` for
|
||||
/// fatal/errors/warnings and `LintDiagnostic` for lints.
|
||||
/// to diagnostic methods for generated diagnostic derives.
|
||||
pub(crate) struct DiagnosticDeriveVariantBuilder {
|
||||
/// The kind for the entire type.
|
||||
pub kind: DiagnosticDeriveKind,
|
||||
|
||||
/// Initialization of format strings for code suggestions.
|
||||
pub formatting_init: TokenStream,
|
||||
|
||||
@@ -51,60 +85,6 @@ pub(crate) struct DiagnosticDeriveVariantBuilder {
|
||||
pub code: SpannedOption<()>,
|
||||
}
|
||||
|
||||
impl DiagnosticDeriveKind {
|
||||
/// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the
|
||||
/// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions
|
||||
/// or attributes on the type itself when input is an enum.
|
||||
pub(crate) fn each_variant<'s, F>(self, structure: &mut Structure<'s>, f: F) -> TokenStream
|
||||
where
|
||||
F: for<'v> Fn(DiagnosticDeriveVariantBuilder, &VariantInfo<'v>) -> TokenStream,
|
||||
{
|
||||
let ast = structure.ast();
|
||||
let span = ast.span().unwrap();
|
||||
match ast.data {
|
||||
syn::Data::Struct(..) | syn::Data::Enum(..) => (),
|
||||
syn::Data::Union(..) => {
|
||||
span_err(span, "diagnostic derives can only be used on structs and enums").emit();
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(ast.data, syn::Data::Enum(..)) {
|
||||
for attr in &ast.attrs {
|
||||
span_err(
|
||||
attr.span().unwrap(),
|
||||
"unsupported type attribute for diagnostic derive enum",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
structure.bind_with(|_| synstructure::BindStyle::Move);
|
||||
let variants = structure.each_variant(|variant| {
|
||||
let span = match structure.ast().data {
|
||||
syn::Data::Struct(..) => span,
|
||||
// There isn't a good way to get the span of the variant, so the variant's
|
||||
// name will need to do.
|
||||
_ => variant.ast().ident.span().unwrap(),
|
||||
};
|
||||
let builder = DiagnosticDeriveVariantBuilder {
|
||||
kind: self,
|
||||
span,
|
||||
field_map: build_field_mapping(variant),
|
||||
formatting_init: TokenStream::new(),
|
||||
message: None,
|
||||
code: None,
|
||||
};
|
||||
f(builder, variant)
|
||||
});
|
||||
|
||||
quote! {
|
||||
match self {
|
||||
#variants
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticDeriveVariantBuilder {
|
||||
pub(crate) fn primary_message(&self) -> Option<&Message> {
|
||||
match self.message.as_ref() {
|
||||
@@ -358,20 +338,11 @@ fn generate_inner_field_code(
|
||||
// `arg` call will not be generated.
|
||||
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
|
||||
(Meta::Path(_), "primary_span") => {
|
||||
match self.kind {
|
||||
DiagnosticDeriveKind::Diagnostic => {
|
||||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
|
||||
return Ok(quote! {
|
||||
diag.span(#binding);
|
||||
});
|
||||
}
|
||||
DiagnosticDeriveKind::LintDiagnostic => {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
|
||||
})
|
||||
}
|
||||
}
|
||||
return Ok(quote! {
|
||||
diag.span(#binding);
|
||||
});
|
||||
}
|
||||
(Meta::Path(_), "subdiagnostic") => {
|
||||
return Ok(quote! { diag.subdiagnostic(#binding); });
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
mod subdiagnostic;
|
||||
mod utils;
|
||||
|
||||
use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
|
||||
use diagnostic::DiagnosticDerive;
|
||||
pub(super) use msg_macro::msg_macro;
|
||||
use proc_macro2::TokenStream;
|
||||
use subdiagnostic::SubdiagnosticDerive;
|
||||
@@ -51,38 +51,6 @@ pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
DiagnosticDerive::new(s).into_tokens()
|
||||
}
|
||||
|
||||
/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
|
||||
/// independent from the actual lint emitting code.
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// #[derive(LintDiagnostic)]
|
||||
/// #[diag("unused attribute")]
|
||||
/// pub(crate) struct UnusedAttribute {
|
||||
/// #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
|
||||
/// pub this: Span,
|
||||
/// #[note("attribute also specified here")]
|
||||
/// pub other: Span,
|
||||
/// #[warning(
|
||||
/// "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
|
||||
/// )]
|
||||
/// pub warning: bool,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Then, later, to emit the error:
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// cx.emit_span_lint(UNUSED_ATTRIBUTES, span, UnusedAttribute {
|
||||
/// ...
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
|
||||
pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
LintDiagnosticDerive::new(s).into_tokens()
|
||||
}
|
||||
|
||||
/// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and
|
||||
/// suggestions to be specified as a structs or enums, independent from the actual diagnostics
|
||||
/// emitting code or diagnostic derives.
|
||||
@@ -99,7 +67,7 @@ pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
/// Then, later, use the subdiagnostic in a diagnostic:
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// #[derive(LintDiagnostic)]
|
||||
/// #[derive(Diagnostic)]
|
||||
/// #[diag("unused doc comment")]
|
||||
/// pub(crate) struct BuiltinUnusedDocComment<'a> {
|
||||
/// pub kind: &'a str,
|
||||
|
||||
@@ -196,25 +196,6 @@ pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
suggestion_hidden,
|
||||
suggestion_verbose)] => diagnostics::diagnostic_derive
|
||||
);
|
||||
decl_derive!(
|
||||
[LintDiagnostic, attributes(
|
||||
// struct attributes
|
||||
diag,
|
||||
help,
|
||||
help_once,
|
||||
note,
|
||||
note_once,
|
||||
warning,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
primary_span,
|
||||
label,
|
||||
subdiagnostic,
|
||||
suggestion,
|
||||
suggestion_short,
|
||||
suggestion_hidden,
|
||||
suggestion_verbose)] => diagnostics::lint_diagnostic_derive
|
||||
);
|
||||
decl_derive!(
|
||||
[Subdiagnostic, attributes(
|
||||
// struct/variant attributes
|
||||
|
||||
Reference in New Issue
Block a user