blob: 2f7c3cc6a46d29ee9921a3926b5c2dd948477c49 [file] [log] [blame] [edit]
#![deny(unused_must_use)]
use proc_macro2::TokenStream;
use quote::quote;
use synstructure::Structure;
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.
pub(crate) struct DiagnosticDerive<'a> {
structure: Structure<'a>,
}
impl<'a> DiagnosticDerive<'a> {
pub(crate) fn new(structure: Structure<'a>) -> Self {
Self { structure }
}
pub(crate) fn into_tokens(self) -> TokenStream {
let DiagnosticDerive { mut structure } = self;
let implementation = 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 init = quote! {
let mut diag = rustc_errors::Diag::new(
dcx,
level,
#message
);
};
let formatting_init = &builder.formatting_init;
quote! {
#init
#formatting_init
#preamble
#body
diag
}
});
// A lifetime of `'a` causes conflicts, but `_sess` is fine.
structure.gen_impl(quote! {
gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self
where G: rustc_errors::EmissionGuarantee
{
#[track_caller]
fn into_diag(
self,
dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level
) -> rustc_errors::Diag<'_sess, G> {
#implementation
}
}
})
}
}