aboutsummaryrefslogtreecommitdiff
path: root/macros/src/util/error.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-01-30 21:29:21 +0100
committerHampusM <hampus@hampusmat.com>2023-01-30 21:29:21 +0100
commit178267c701c233542078c09fe6b19802f9642dbd (patch)
tree3d3010806f6509c062ca86dbbbe9c3a6cd2fe547 /macros/src/util/error.rs
parent17ca46e95af38a914197958bbcc1e759865b6005 (diff)
feat: improve macro error messages
Diffstat (limited to 'macros/src/util/error.rs')
-rw-r--r--macros/src/util/error.rs116
1 files changed, 116 insertions, 0 deletions
diff --git a/macros/src/util/error.rs b/macros/src/util/error.rs
new file mode 100644
index 0000000..d068661
--- /dev/null
+++ b/macros/src/util/error.rs
@@ -0,0 +1,116 @@
+/// Used to create a error enum that converts into a [`Diagnostic`].
+///
+/// [`Diagnostic`]: proc_macro_error::Diagnostic
+macro_rules! diagnostic_error_enum {
+ ($(#[$meta: meta])* $visibility: vis enum $name: ident {
+ $(
+ #[error($($error: tt)*), span = $error_span: expr]
+ $(#[note($($note: tt)*)$(, span = $note_span: expr)?])*
+ $(#[help($($help: tt)*)$(, span = $help_span: expr)?])*
+ $(#[err($($err: tt)*)$(, span = $err_span: expr)?])*
+ $(#[source($source: ident)])?
+ $variant: ident {
+ $($variant_field: ident: $variant_field_type: ty),*
+ },
+ )*
+ }) => {
+ $(#[$meta])*
+ #[derive(Debug, Clone)]
+ $visibility enum $name
+ {
+ $(
+ $variant {
+ $($variant_field: $variant_field_type),*
+ },
+ )*
+ }
+
+ impl From<$name> for ::proc_macro_error::Diagnostic
+ {
+ #[must_use]
+ fn from(err: $name) -> Self
+ {
+ let (error, span, notes, helps, errs, source): (
+ String,
+ ::proc_macro2::Span,
+ Vec<(String, ::proc_macro2::Span)>,
+ Vec<(String, ::proc_macro2::Span)>,
+ Vec<(String, ::proc_macro2::Span)>,
+ Option<::proc_macro_error::Diagnostic>
+ ) = match err {
+ $(
+ $name::$variant {
+ $($variant_field),*
+ } => {
+ (
+ format!($($error)*),
+ $error_span,
+ vec![$(
+ (
+ format!($($note)*),
+ $crate::util::or!(
+ ($($note_span)?)
+ else (::proc_macro2::Span::call_site())
+ )
+ )
+ ),*],
+ vec![$(
+ (
+ format!($($help)*),
+ $crate::util::or!(
+ ($($help_span)?)
+ else (::proc_macro2::Span::call_site())
+ )
+ )
+ ),*],
+ vec![$(
+ (
+ format!($($err)*),
+ $crate::util::or!(
+ ($($err_span)?)
+ else (::proc_macro2::Span::call_site())
+ )
+ )
+ ),*],
+ $crate::util::to_option!($($source.into())?)
+ )
+ }
+ ),*
+ };
+
+ if let Some(source_diagnostic) = source {
+ source_diagnostic.emit();
+ }
+
+ let mut diagnostic = ::proc_macro_error::Diagnostic::spanned(
+ span,
+ ::proc_macro_error::Level::Error,
+ error
+ );
+
+ if !notes.is_empty() {
+ for (note, note_span) in notes {
+ diagnostic = diagnostic.span_note(note_span, note);
+ }
+ }
+
+ if !helps.is_empty() {
+ for (help, help_span) in helps {
+ diagnostic = diagnostic.span_help(help_span, help);
+ }
+ }
+
+ if !errs.is_empty() {
+ for (err, err_span) in errs {
+ diagnostic = diagnostic.span_error(err_span, err);
+ }
+ }
+
+ diagnostic
+ }
+ }
+
+ };
+}
+
+pub(crate) use diagnostic_error_enum;