flux_macros/diagnostics/
error.rs1use proc_macro::{Diagnostic, Level, MultiSpan};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{Attribute, Error as SynError, Meta, spanned::Spanned};
5
6#[derive(Debug)]
7pub(crate) enum DiagnosticDeriveError {
8 SynError(SynError),
9 ErrorHandled,
10}
11
12impl DiagnosticDeriveError {
13 pub(crate) fn to_compile_error(self) -> TokenStream {
14 match self {
15 DiagnosticDeriveError::SynError(e) => e.to_compile_error(),
16 DiagnosticDeriveError::ErrorHandled => {
17 quote! {
20 { unreachable!(); }
21 }
22 }
23 }
24 }
25}
26
27impl From<SynError> for DiagnosticDeriveError {
28 fn from(e: SynError) -> Self {
29 DiagnosticDeriveError::SynError(e)
30 }
31}
32
33pub(crate) fn _throw_err(
35 diag: Diagnostic,
36 f: impl FnOnce(Diagnostic) -> Diagnostic,
37) -> DiagnosticDeriveError {
38 f(diag).emit();
39 DiagnosticDeriveError::ErrorHandled
40}
41
42fn path_to_string(path: &syn::Path) -> String {
45 let mut out = String::new();
46 for (i, segment) in path.segments.iter().enumerate() {
47 if i > 0 || path.leading_colon.is_some() {
48 out.push_str("::");
49 }
50 out.push_str(&segment.ident.to_string());
51 }
52 out
53}
54
55#[must_use]
57pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic {
58 Diagnostic::spanned(span, Level::Error, msg)
59}
60
61macro_rules! throw_span_err {
66 ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
67 ($span:expr, $msg:expr, $f:expr) => {{
68 let diag = span_err($span, $msg);
69 return Err(crate::diagnostics::error::_throw_err(diag, $f));
70 }};
71}
72
73pub(crate) use throw_span_err;
74
75pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic {
77 let span = attr.span().unwrap();
78 let path = path_to_string(attr.path());
79 match attr.meta {
80 Meta::Path(_) => span_err(span, format!("`#[{path}]` is not a valid attribute")),
81 Meta::NameValue(_) => span_err(span, format!("`#[{path} = ...]` is not a valid attribute")),
82 Meta::List(_) => span_err(span, format!("`#[{path}(...)]` is not a valid attribute")),
83 }
84}
85
86macro_rules! throw_invalid_attr {
91 ($attr:expr) => {{ throw_invalid_attr!($attr, |diag| diag) }};
92 ($attr:expr, $f:expr) => {{
93 let diag = crate::diagnostics::error::invalid_attr($attr);
94 return Err(crate::diagnostics::error::_throw_err(diag, $f));
95 }};
96}
97
98pub(crate) use throw_invalid_attr;