| #![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(); | |
| 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 | |
| } | |
| } | |
| }) | |
| } | |
| } |