diff options
Diffstat (limited to 'vendor/miette-derive/src/diagnostic.rs')
-rw-r--r-- | vendor/miette-derive/src/diagnostic.rs | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/vendor/miette-derive/src/diagnostic.rs b/vendor/miette-derive/src/diagnostic.rs deleted file mode 100644 index 0173d2a..0000000 --- a/vendor/miette-derive/src/diagnostic.rs +++ /dev/null @@ -1,397 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{punctuated::Punctuated, DeriveInput, Token}; - -use crate::code::Code; -use crate::diagnostic_arg::DiagnosticArg; -use crate::diagnostic_source::DiagnosticSource; -use crate::forward::{Forward, WhichFn}; -use crate::help::Help; -use crate::label::Labels; -use crate::related::Related; -use crate::severity::Severity; -use crate::source_code::SourceCode; -use crate::url::Url; - -pub enum Diagnostic { - Struct { - generics: syn::Generics, - ident: syn::Ident, - fields: syn::Fields, - args: DiagnosticDefArgs, - }, - Enum { - ident: syn::Ident, - generics: syn::Generics, - variants: Vec<DiagnosticDef>, - }, -} - -pub struct DiagnosticDef { - pub ident: syn::Ident, - pub fields: syn::Fields, - pub args: DiagnosticDefArgs, -} - -pub enum DiagnosticDefArgs { - Transparent(Forward), - Concrete(Box<DiagnosticConcreteArgs>), -} - -impl DiagnosticDefArgs { - pub(crate) fn forward_or_override_enum( - &self, - variant: &syn::Ident, - which_fn: WhichFn, - mut f: impl FnMut(&DiagnosticConcreteArgs) -> Option<TokenStream>, - ) -> Option<TokenStream> { - match self { - Self::Transparent(forward) => Some(forward.gen_enum_match_arm(variant, which_fn)), - Self::Concrete(concrete) => f(concrete).or_else(|| { - concrete - .forward - .as_ref() - .map(|forward| forward.gen_enum_match_arm(variant, which_fn)) - }), - } - } -} - -#[derive(Default)] -pub struct DiagnosticConcreteArgs { - pub code: Option<Code>, - pub severity: Option<Severity>, - pub help: Option<Help>, - pub labels: Option<Labels>, - pub source_code: Option<SourceCode>, - pub url: Option<Url>, - pub forward: Option<Forward>, - pub related: Option<Related>, - pub diagnostic_source: Option<DiagnosticSource>, -} - -impl DiagnosticConcreteArgs { - fn for_fields(fields: &syn::Fields) -> Result<Self, syn::Error> { - let labels = Labels::from_fields(fields)?; - let source_code = SourceCode::from_fields(fields)?; - let related = Related::from_fields(fields)?; - let help = Help::from_fields(fields)?; - let diagnostic_source = DiagnosticSource::from_fields(fields)?; - Ok(DiagnosticConcreteArgs { - code: None, - help, - related, - severity: None, - labels, - url: None, - forward: None, - source_code, - diagnostic_source, - }) - } - - fn add_args( - &mut self, - attr: &syn::Attribute, - args: impl Iterator<Item = DiagnosticArg>, - errors: &mut Vec<syn::Error>, - ) { - for arg in args { - match arg { - DiagnosticArg::Transparent => { - errors.push(syn::Error::new_spanned(attr, "transparent not allowed")); - } - DiagnosticArg::Forward(to_field) => { - if self.forward.is_some() { - errors.push(syn::Error::new_spanned( - attr, - "forward has already been specified", - )); - } - self.forward = Some(to_field); - } - DiagnosticArg::Code(new_code) => { - if self.code.is_some() { - errors.push(syn::Error::new_spanned( - attr, - "code has already been specified", - )); - } - self.code = Some(new_code); - } - DiagnosticArg::Severity(sev) => { - if self.severity.is_some() { - errors.push(syn::Error::new_spanned( - attr, - "severity has already been specified", - )); - } - self.severity = Some(sev); - } - DiagnosticArg::Help(hl) => { - if self.help.is_some() { - errors.push(syn::Error::new_spanned( - attr, - "help has already been specified", - )); - } - self.help = Some(hl); - } - DiagnosticArg::Url(u) => { - if self.url.is_some() { - errors.push(syn::Error::new_spanned( - attr, - "url has already been specified", - )); - } - self.url = Some(u); - } - } - } - } -} - -impl DiagnosticDefArgs { - fn parse( - _ident: &syn::Ident, - fields: &syn::Fields, - attrs: &[&syn::Attribute], - allow_transparent: bool, - ) -> syn::Result<Self> { - let mut errors = Vec::new(); - - // Handle the only condition where Transparent is allowed - if allow_transparent && attrs.len() == 1 { - if let Ok(args) = - attrs[0].parse_args_with(Punctuated::<DiagnosticArg, Token![,]>::parse_terminated) - { - if matches!(args.first(), Some(DiagnosticArg::Transparent)) { - let forward = Forward::for_transparent_field(fields)?; - return Ok(Self::Transparent(forward)); - } - } - } - - // Create errors for any appearances of Transparent - let error_message = if allow_transparent { - "diagnostic(transparent) not allowed in combination with other args" - } else { - "diagnostic(transparent) not allowed here" - }; - fn is_transparent(d: &DiagnosticArg) -> bool { - matches!(d, DiagnosticArg::Transparent) - } - - let mut concrete = DiagnosticConcreteArgs::for_fields(fields)?; - for attr in attrs { - let args = - attr.parse_args_with(Punctuated::<DiagnosticArg, Token![,]>::parse_terminated); - let args = match args { - Ok(args) => args, - Err(error) => { - errors.push(error); - continue; - } - }; - - if args.iter().any(is_transparent) { - errors.push(syn::Error::new_spanned(attr, error_message)); - } - - let args = args - .into_iter() - .filter(|x| !matches!(x, DiagnosticArg::Transparent)); - - concrete.add_args(attr, args, &mut errors); - } - - let combined_error = errors.into_iter().reduce(|mut lhs, rhs| { - lhs.combine(rhs); - lhs - }); - if let Some(error) = combined_error { - Err(error) - } else { - Ok(DiagnosticDefArgs::Concrete(Box::new(concrete))) - } - } -} - -impl Diagnostic { - pub fn from_derive_input(input: DeriveInput) -> Result<Self, syn::Error> { - let input_attrs = input - .attrs - .iter() - .filter(|x| x.path().is_ident("diagnostic")) - .collect::<Vec<&syn::Attribute>>(); - Ok(match input.data { - syn::Data::Struct(data_struct) => { - let args = DiagnosticDefArgs::parse( - &input.ident, - &data_struct.fields, - &input_attrs, - true, - )?; - - Diagnostic::Struct { - fields: data_struct.fields, - ident: input.ident, - generics: input.generics, - args, - } - } - syn::Data::Enum(syn::DataEnum { variants, .. }) => { - let mut vars = Vec::new(); - for var in variants { - let mut variant_attrs = input_attrs.clone(); - variant_attrs - .extend(var.attrs.iter().filter(|x| x.path().is_ident("diagnostic"))); - let args = - DiagnosticDefArgs::parse(&var.ident, &var.fields, &variant_attrs, true)?; - vars.push(DiagnosticDef { - ident: var.ident, - fields: var.fields, - args, - }); - } - Diagnostic::Enum { - ident: input.ident, - generics: input.generics, - variants: vars, - } - } - syn::Data::Union(_) => { - return Err(syn::Error::new( - input.ident.span(), - "Can't derive Diagnostic for Unions", - )) - } - }) - } - - pub fn gen(&self) -> TokenStream { - match self { - Self::Struct { - ident, - fields, - generics, - args, - } => { - let (impl_generics, ty_generics, where_clause) = &generics.split_for_impl(); - match args { - DiagnosticDefArgs::Transparent(forward) => { - let code_method = forward.gen_struct_method(WhichFn::Code); - let help_method = forward.gen_struct_method(WhichFn::Help); - let url_method = forward.gen_struct_method(WhichFn::Url); - let labels_method = forward.gen_struct_method(WhichFn::Labels); - let source_code_method = forward.gen_struct_method(WhichFn::SourceCode); - let severity_method = forward.gen_struct_method(WhichFn::Severity); - let related_method = forward.gen_struct_method(WhichFn::Related); - let diagnostic_source_method = - forward.gen_struct_method(WhichFn::DiagnosticSource); - - quote! { - impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause { - #code_method - #help_method - #url_method - #labels_method - #severity_method - #source_code_method - #related_method - #diagnostic_source_method - } - } - } - DiagnosticDefArgs::Concrete(concrete) => { - let forward = |which| { - concrete - .forward - .as_ref() - .map(|fwd| fwd.gen_struct_method(which)) - }; - let code_body = concrete - .code - .as_ref() - .and_then(|x| x.gen_struct()) - .or_else(|| forward(WhichFn::Code)); - let help_body = concrete - .help - .as_ref() - .and_then(|x| x.gen_struct(fields)) - .or_else(|| forward(WhichFn::Help)); - let sev_body = concrete - .severity - .as_ref() - .and_then(|x| x.gen_struct()) - .or_else(|| forward(WhichFn::Severity)); - let rel_body = concrete - .related - .as_ref() - .and_then(|x| x.gen_struct()) - .or_else(|| forward(WhichFn::Related)); - let url_body = concrete - .url - .as_ref() - .and_then(|x| x.gen_struct(ident, fields)) - .or_else(|| forward(WhichFn::Url)); - let labels_body = concrete - .labels - .as_ref() - .and_then(|x| x.gen_struct(fields)) - .or_else(|| forward(WhichFn::Labels)); - let src_body = concrete - .source_code - .as_ref() - .and_then(|x| x.gen_struct(fields)) - .or_else(|| forward(WhichFn::SourceCode)); - let diagnostic_source = concrete - .diagnostic_source - .as_ref() - .and_then(|x| x.gen_struct()) - .or_else(|| forward(WhichFn::DiagnosticSource)); - quote! { - impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause { - #code_body - #help_body - #sev_body - #rel_body - #url_body - #labels_body - #src_body - #diagnostic_source - } - } - } - } - } - Self::Enum { - ident, - generics, - variants, - } => { - let (impl_generics, ty_generics, where_clause) = &generics.split_for_impl(); - let code_body = Code::gen_enum(variants); - let help_body = Help::gen_enum(variants); - let sev_body = Severity::gen_enum(variants); - let labels_body = Labels::gen_enum(variants); - let src_body = SourceCode::gen_enum(variants); - let rel_body = Related::gen_enum(variants); - let url_body = Url::gen_enum(ident, variants); - let diagnostic_source_body = DiagnosticSource::gen_enum(variants); - quote! { - impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause { - #code_body - #help_body - #sev_body - #labels_body - #src_body - #rel_body - #url_body - #diagnostic_source_body - } - } - } - } - } -} |