macros: support diagnostic derive on enums
Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
72f4923979
commit
f20c882b8b
6 changed files with 370 additions and 307 deletions
|
@ -2,10 +2,9 @@
|
|||
|
||||
use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
|
||||
use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
|
||||
use crate::diagnostics::utils::{build_field_mapping, SetOnce};
|
||||
use crate::diagnostics::utils::SetOnce;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
use synstructure::Structure;
|
||||
|
||||
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
|
||||
|
@ -18,13 +17,7 @@ pub(crate) struct DiagnosticDerive<'a> {
|
|||
impl<'a> DiagnosticDerive<'a> {
|
||||
pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
|
||||
Self {
|
||||
builder: DiagnosticDeriveBuilder {
|
||||
diag,
|
||||
fields: build_field_mapping(&structure),
|
||||
kind: DiagnosticDeriveKind::Diagnostic,
|
||||
code: None,
|
||||
slug: None,
|
||||
},
|
||||
builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::Diagnostic },
|
||||
handler,
|
||||
structure,
|
||||
}
|
||||
|
@ -33,52 +26,35 @@ impl<'a> DiagnosticDerive<'a> {
|
|||
pub(crate) fn into_tokens(self) -> TokenStream {
|
||||
let DiagnosticDerive { mut structure, handler, mut builder } = self;
|
||||
|
||||
let ast = structure.ast();
|
||||
let implementation = {
|
||||
if let syn::Data::Struct(..) = ast.data {
|
||||
let preamble = builder.preamble(&structure);
|
||||
let (attrs, args) = builder.body(&mut structure);
|
||||
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
|
||||
let preamble = builder.preamble(&variant);
|
||||
let body = builder.body(&variant);
|
||||
|
||||
let span = ast.span().unwrap();
|
||||
let diag = &builder.diag;
|
||||
let init = match builder.slug.value() {
|
||||
None => {
|
||||
span_err(span, "diagnostic slug not specified")
|
||||
.help(&format!(
|
||||
"specify the slug as the first argument to the `#[diag(...)]` attribute, \
|
||||
such as `#[diag(typeck::example_error)]`",
|
||||
))
|
||||
.emit();
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
}
|
||||
Some(slug) => {
|
||||
quote! {
|
||||
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#init
|
||||
#preamble
|
||||
match self {
|
||||
#attrs
|
||||
}
|
||||
match self {
|
||||
#args
|
||||
}
|
||||
#diag
|
||||
let diag = &builder.parent.diag;
|
||||
let init = match builder.slug.value_ref() {
|
||||
None => {
|
||||
span_err(builder.span, "diagnostic slug not specified")
|
||||
.help(&format!(
|
||||
"specify the slug as the first argument to the `#[diag(...)]` \
|
||||
attribute, such as `#[diag(typeck::example_error)]`",
|
||||
))
|
||||
.emit();
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
}
|
||||
} else {
|
||||
span_err(
|
||||
ast.span().unwrap(),
|
||||
"`#[derive(Diagnostic)]` can only be used on structs",
|
||||
)
|
||||
.emit();
|
||||
Some(slug) => {
|
||||
quote! {
|
||||
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DiagnosticDeriveError::ErrorHandled.to_compile_error()
|
||||
quote! {
|
||||
#init
|
||||
#preamble
|
||||
#body
|
||||
#diag
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
structure.gen_impl(quote! {
|
||||
gen impl<'__diagnostic_handler_sess, G>
|
||||
|
@ -107,13 +83,7 @@ pub(crate) struct LintDiagnosticDerive<'a> {
|
|||
impl<'a> LintDiagnosticDerive<'a> {
|
||||
pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self {
|
||||
Self {
|
||||
builder: DiagnosticDeriveBuilder {
|
||||
diag,
|
||||
fields: build_field_mapping(&structure),
|
||||
kind: DiagnosticDeriveKind::LintDiagnostic,
|
||||
code: None,
|
||||
slug: None,
|
||||
},
|
||||
builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::LintDiagnostic },
|
||||
structure,
|
||||
}
|
||||
}
|
||||
|
@ -121,54 +91,35 @@ impl<'a> LintDiagnosticDerive<'a> {
|
|||
pub(crate) fn into_tokens(self) -> TokenStream {
|
||||
let LintDiagnosticDerive { mut structure, mut builder } = self;
|
||||
|
||||
let ast = structure.ast();
|
||||
let implementation = {
|
||||
if let syn::Data::Struct(..) = ast.data {
|
||||
let preamble = builder.preamble(&structure);
|
||||
let (attrs, args) = builder.body(&mut structure);
|
||||
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
|
||||
let preamble = builder.preamble(&variant);
|
||||
let body = builder.body(&variant);
|
||||
|
||||
let diag = &builder.diag;
|
||||
let span = ast.span().unwrap();
|
||||
let init = match builder.slug.value() {
|
||||
None => {
|
||||
span_err(span, "diagnostic slug not specified")
|
||||
.help(&format!(
|
||||
"specify the slug as the first argument to the attribute, such as \
|
||||
`#[diag(typeck::example_error)]`",
|
||||
))
|
||||
.emit();
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
let diag = &builder.parent.diag;
|
||||
let init = match builder.slug.value_ref() {
|
||||
None => {
|
||||
span_err(builder.span, "diagnostic slug not specified")
|
||||
.help(&format!(
|
||||
"specify the slug as the first argument to the attribute, such as \
|
||||
`#[diag(typeck::example_error)]`",
|
||||
))
|
||||
.emit();
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
}
|
||||
Some(slug) => {
|
||||
quote! {
|
||||
let mut #diag = #diag.build(rustc_errors::fluent::#slug);
|
||||
}
|
||||
Some(slug) => {
|
||||
quote! {
|
||||
let mut #diag = #diag.build(rustc_errors::fluent::#slug);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let implementation = quote! {
|
||||
#init
|
||||
#preamble
|
||||
match self {
|
||||
#attrs
|
||||
}
|
||||
match self {
|
||||
#args
|
||||
}
|
||||
#diag.emit();
|
||||
};
|
||||
|
||||
implementation
|
||||
} else {
|
||||
span_err(
|
||||
ast.span().unwrap(),
|
||||
"`#[derive(LintDiagnostic)]` can only be used on structs",
|
||||
)
|
||||
.emit();
|
||||
|
||||
DiagnosticDeriveError::ErrorHandled.to_compile_error()
|
||||
quote! {
|
||||
#init
|
||||
#preamble
|
||||
#body
|
||||
#diag.emit();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let diag = &builder.diag;
|
||||
structure.gen_impl(quote! {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue