1 use proc_macro
::{Diagnostic, Level, MultiSpan}
;
2 use proc_macro2
::TokenStream
;
4 use syn
::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta}
;
7 pub(crate) enum DiagnosticDeriveError
{
12 impl DiagnosticDeriveError
{
13 pub(crate) fn to_compile_error(self) -> TokenStream
{
15 DiagnosticDeriveError
::SynError(e
) => e
.to_compile_error(),
16 DiagnosticDeriveError
::ErrorHandled
=> {
17 // Return ! to avoid having to create a blank DiagnosticBuilder to return when an
18 // error has already been emitted to the compiler.
27 impl From
<SynError
> for DiagnosticDeriveError
{
28 fn from(e
: SynError
) -> Self {
29 DiagnosticDeriveError
::SynError(e
)
33 /// Helper function for use with `throw_*` macros - constraints `$f` to an `impl FnOnce`.
34 pub(crate) fn _throw_err(
36 f
: impl FnOnce(Diagnostic
) -> Diagnostic
,
37 ) -> DiagnosticDeriveError
{
39 DiagnosticDeriveError
::ErrorHandled
42 /// Helper function for printing `syn::Path` - doesn't handle arguments in paths and these are
43 /// unlikely to come up much in use of the macro.
44 fn 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() {
50 out
.push_str(&segment
.ident
.to_string());
55 /// Returns an error diagnostic on span `span` with msg `msg`.
56 pub(crate) fn span_err(span
: impl MultiSpan
, msg
: &str) -> Diagnostic
{
57 Diagnostic
::spanned(span
, Level
::Error
, msg
)
60 /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
61 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
63 /// For methods that return a `Result<_, DiagnosticDeriveError>`:
64 macro_rules
! throw_span_err
{
65 ($span
:expr
, $msg
:expr
) => {{ throw_span_err!($span, $msg, |diag| diag) }
};
66 ($span
:expr
, $msg
:expr
, $f
:expr
) => {{
67 let diag
= span_err($span
, $msg
);
68 return Err(crate::diagnostics
::error
::_throw_err(diag
, $f
));
72 pub(crate) use throw_span_err
;
74 /// Returns an error diagnostic for an invalid attribute.
75 pub(crate) fn invalid_attr(attr
: &Attribute
, meta
: &Meta
) -> Diagnostic
{
76 let span
= attr
.span().unwrap();
77 let path
= path_to_string(&attr
.path
);
79 Meta
::Path(_
) => span_err(span
, &format
!("`#[{path}]` is not a valid attribute")),
80 Meta
::NameValue(_
) => {
81 span_err(span
, &format
!("`#[{path} = ...]` is not a valid attribute"))
83 Meta
::List(_
) => span_err(span
, &format
!("`#[{path}(...)]` is not a valid attribute")),
87 /// Emit an error diagnostic for an invalid attribute (optionally performing additional decoration
88 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
90 /// For methods that return a `Result<_, DiagnosticDeriveError>`:
91 macro_rules
! throw_invalid_attr
{
92 ($attr
:expr
, $meta
:expr
) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }
};
93 ($attr
:expr
, $meta
:expr
, $f
:expr
) => {{
94 let diag
= crate::diagnostics
::error
::invalid_attr($attr
, $meta
);
95 return Err(crate::diagnostics
::error
::_throw_err(diag
, $f
));
99 pub(crate) use throw_invalid_attr
;
101 /// Returns an error diagnostic for an invalid nested attribute.
102 pub(crate) fn invalid_nested_attr(attr
: &Attribute
, nested
: &NestedMeta
) -> Diagnostic
{
103 let name
= attr
.path
.segments
.last().unwrap().ident
.to_string();
104 let name
= name
.as_str();
106 let span
= nested
.span().unwrap();
107 let meta
= match nested
{
108 syn
::NestedMeta
::Meta(meta
) => meta
,
109 syn
::NestedMeta
::Lit(_
) => {
110 return span_err(span
, &format
!("`#[{name}(\"...\")]` is not a valid attribute"));
114 let span
= meta
.span().unwrap();
115 let path
= path_to_string(meta
.path());
117 Meta
::NameValue(..) => {
118 span_err(span
, &format
!("`#[{name}({path} = ...)]` is not a valid attribute"))
120 Meta
::Path(..) => span_err(span
, &format
!("`#[{name}({path})]` is not a valid attribute")),
122 span_err(span
, &format
!("`#[{name}({path}(...))]` is not a valid attribute"))
127 /// Emit an error diagnostic for an invalid nested attribute (optionally performing additional
128 /// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
130 /// For methods that return a `Result<_, DiagnosticDeriveError>`:
131 macro_rules
! throw_invalid_nested_attr
{
132 ($attr
:expr
, $nested_attr
:expr
) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }
};
133 ($attr
:expr
, $nested_attr
:expr
, $f
:expr
) => {{
134 let diag
= crate::diagnostics
::error
::invalid_nested_attr($attr
, $nested_attr
);
135 return Err(crate::diagnostics
::error
::_throw_err(diag
, $f
));
139 pub(crate) use throw_invalid_nested_attr
;