macros: note/help in SessionDiagnostic
derive
Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
a88717cef0
commit
b40ee88a28
4 changed files with 159 additions and 11 deletions
|
@ -66,6 +66,8 @@ decl_derive!(
|
||||||
// struct attributes
|
// struct attributes
|
||||||
warning,
|
warning,
|
||||||
error,
|
error,
|
||||||
|
note,
|
||||||
|
help,
|
||||||
// field attributes
|
// field attributes
|
||||||
skip_arg,
|
skip_arg,
|
||||||
primary_span,
|
primary_span,
|
||||||
|
|
|
@ -362,18 +362,52 @@ struct SessionDiagnosticDeriveBuilder<'a> {
|
||||||
|
|
||||||
impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||||
/// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
|
/// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
|
||||||
/// attributes like `#[error(..)#`, such as the diagnostic kind, slug and code.
|
/// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates
|
||||||
///
|
/// diagnostic builder calls for setting error code and creating note/help messages.
|
||||||
/// Returns a `proc_macro2::TokenStream` so that the `Err(..)` variant can be transformed into
|
|
||||||
/// the same type via `to_compile_error`.
|
|
||||||
fn generate_structure_code(
|
fn generate_structure_code(
|
||||||
&mut self,
|
&mut self,
|
||||||
attr: &syn::Attribute,
|
attr: &syn::Attribute,
|
||||||
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
|
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
|
||||||
let span = attr.span().unwrap();
|
let span = attr.span().unwrap();
|
||||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
|
||||||
|
|
||||||
let nested = match attr.parse_meta()? {
|
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||||
|
let name = name.as_str();
|
||||||
|
let meta = attr.parse_meta()?;
|
||||||
|
|
||||||
|
if matches!(name, "help" | "note")
|
||||||
|
&& matches!(meta, syn::Meta::Path(_) | syn::Meta::NameValue(_))
|
||||||
|
{
|
||||||
|
let diag = &self.diag;
|
||||||
|
let slug = match &self.slug {
|
||||||
|
Some((slug, _)) => slug.as_str(),
|
||||||
|
None => throw_span_err!(
|
||||||
|
span,
|
||||||
|
&format!(
|
||||||
|
"`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`",
|
||||||
|
name,
|
||||||
|
match meta {
|
||||||
|
syn::Meta::Path(_) => "",
|
||||||
|
syn::Meta::NameValue(_) => " = ...",
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let id = match meta {
|
||||||
|
syn::Meta::Path(..) => quote! { #name },
|
||||||
|
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
|
||||||
|
quote! { #s }
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let fn_name = proc_macro2::Ident::new(name, attr.span());
|
||||||
|
|
||||||
|
return Ok(quote! {
|
||||||
|
#diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let nested = match meta {
|
||||||
syn::Meta::List(syn::MetaList { nested, .. }) => nested,
|
syn::Meta::List(syn::MetaList { nested, .. }) => nested,
|
||||||
syn::Meta::Path(..) => throw_span_err!(
|
syn::Meta::Path(..) => throw_span_err!(
|
||||||
span,
|
span,
|
||||||
|
@ -385,7 +419,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let kind = match name.as_str() {
|
let kind = match name {
|
||||||
"error" => SessionDiagnosticKind::Error,
|
"error" => SessionDiagnosticKind::Error,
|
||||||
"warning" => SessionDiagnosticKind::Warn,
|
"warning" => SessionDiagnosticKind::Warn,
|
||||||
other => throw_span_err!(
|
other => throw_span_err!(
|
||||||
|
@ -579,9 +613,9 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||||
#diag.set_span(*#field_binding);
|
#diag.set_span(*#field_binding);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
"label" => {
|
"label" | "note" | "help" => {
|
||||||
self.report_error_if_not_applied_to_span(attr, info)?;
|
self.report_error_if_not_applied_to_span(attr, info)?;
|
||||||
Ok(self.add_subdiagnostic(field_binding, name, "label"))
|
Ok(self.add_subdiagnostic(field_binding, name, name))
|
||||||
}
|
}
|
||||||
other => throw_span_err!(
|
other => throw_span_err!(
|
||||||
attr.span().unwrap(),
|
attr.span().unwrap(),
|
||||||
|
@ -589,7 +623,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name {
|
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name {
|
||||||
"label" => {
|
"label" | "note" | "help" => {
|
||||||
self.report_error_if_not_applied_to_span(attr, info)?;
|
self.report_error_if_not_applied_to_span(attr, info)?;
|
||||||
Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
|
Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,3 +339,91 @@ struct ArgFieldWithSkip {
|
||||||
#[skip_arg]
|
#[skip_arg]
|
||||||
other: Hello,
|
other: Hello,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithSpannedNote {
|
||||||
|
#[note]
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithSpannedNoteCustom {
|
||||||
|
#[note = "bar"]
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
#[note]
|
||||||
|
struct ErrorWithNote {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
#[note = "bar"]
|
||||||
|
struct ErrorWithNoteCustom {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithSpannedHelp {
|
||||||
|
#[help]
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithSpannedHelpCustom {
|
||||||
|
#[help = "bar"]
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
#[help]
|
||||||
|
struct ErrorWithHelp {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
#[help = "bar"]
|
||||||
|
struct ErrorWithHelpCustom {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[help]
|
||||||
|
//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithHelpWrongOrder {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[help = "bar"]
|
||||||
|
//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithHelpCustomWrongOrder {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[note]
|
||||||
|
//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithNoteWrongOrder {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[note = "bar"]
|
||||||
|
//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct ErrorWithNoteCustomWrongOrder {
|
||||||
|
val: String,
|
||||||
|
}
|
||||||
|
|
|
@ -249,6 +249,30 @@ error: invalid annotation list `#[label(...)]`
|
||||||
LL | #[label("bar")]
|
LL | #[label("bar")]
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
--> $DIR/session-derive-errors.rs:400:1
|
||||||
|
|
|
||||||
|
LL | #[help]
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
--> $DIR/session-derive-errors.rs:408:1
|
||||||
|
|
|
||||||
|
LL | #[help = "bar"]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
--> $DIR/session-derive-errors.rs:416:1
|
||||||
|
|
|
||||||
|
LL | #[note]
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
|
||||||
|
--> $DIR/session-derive-errors.rs:424:1
|
||||||
|
|
|
||||||
|
LL | #[note = "bar"]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `nonsense` in this scope
|
error: cannot find attribute `nonsense` in this scope
|
||||||
--> $DIR/session-derive-errors.rs:51:3
|
--> $DIR/session-derive-errors.rs:51:3
|
||||||
|
|
|
|
||||||
|
@ -272,6 +296,6 @@ LL | #[derive(SessionDiagnostic)]
|
||||||
|
|
|
|
||||||
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 34 previous errors
|
error: aborting due to 38 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0599`.
|
For more information about this error, try `rustc --explain E0599`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue