diff options
| author | David Wood <david.wood@huawei.com> | 2022-03-31 10:24:46 +0100 |
|---|---|---|
| committer | David Wood <david.wood@huawei.com> | 2022-04-05 07:01:03 +0100 |
| commit | a88717cef051b8ebbed0e74c57fc0a714bd893dc (patch) | |
| tree | da04f2a5e842261b84379a6b240700367f6127e5 /compiler/rustc_macros/src/session_diagnostic.rs | |
| parent | 72dec56028d848ba18a7e1a9bf9da0b6faf5f7da (diff) | |
| download | rust-a88717cef051b8ebbed0e74c57fc0a714bd893dc.tar.gz rust-a88717cef051b8ebbed0e74c57fc0a714bd893dc.zip | |
macros: support translatable labels
Extends support for generating `DiagnosticMessage::FluentIdentifier` messages from `SessionDiagnostic` derive to `#[label]`. Signed-off-by: David Wood <david.wood@huawei.com>
Diffstat (limited to 'compiler/rustc_macros/src/session_diagnostic.rs')
| -rw-r--r-- | compiler/rustc_macros/src/session_diagnostic.rs | 109 |
1 files changed, 75 insertions, 34 deletions
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index 79086931d5f..efbffabbd03 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -561,6 +561,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> { let diag = &self.diag; let field_binding = &info.binding.binding; + let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); @@ -573,46 +574,38 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { Ok(quote! {}) } "primary_span" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - return Ok(quote! { - #diag.set_span(*#field_binding); - }); - } else { - throw_span_err!( - attr.span().unwrap(), - "the `#[primary_span]` attribute can only be applied to fields of type `Span`" - ); - } + self.report_error_if_not_applied_to_span(attr, info)?; + Ok(quote! { + #diag.set_span(*#field_binding); + }) + } + "label" => { + self.report_error_if_not_applied_to_span(attr, info)?; + Ok(self.add_subdiagnostic(field_binding, name, "label")) } other => throw_span_err!( attr.span().unwrap(), &format!("`#[{}]` is not a valid `SessionDiagnostic` field attribute", other) ), }, - syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - let formatted_str = self.build_format(&s.value(), attr.span()); - match name { - "label" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - return Ok(quote! { - #diag.span_label(*#field_binding, #formatted_str); - }); - } else { - throw_span_err!( - attr.span().unwrap(), - "the `#[label = ...]` attribute can only be applied to fields of type `Span`" - ); - } - } - other => throw_span_err!( - attr.span().unwrap(), - &format!( - "`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute", - other - ) - ), + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name { + "label" => { + self.report_error_if_not_applied_to_span(attr, info)?; + Ok(self.add_subdiagnostic(field_binding, name, &s.value())) } - } + other => throw_span_err!( + attr.span().unwrap(), + &format!( + "`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute", + other + ) + ), + }, + syn::Meta::NameValue(_) => throw_span_err!( + attr.span().unwrap(), + &format!("`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute", name), + |diag| diag.help("value must be a string") + ), syn::Meta::List(list) => { match list.path.segments.iter().last().unwrap().ident.to_string().as_str() { suggestion_kind @ "suggestion" @@ -681,7 +674,55 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { ), } } - _ => panic!("unhandled meta kind"), + } + } + + /// Reports an error if the field's type is not `Span`. + fn report_error_if_not_applied_to_span( + &self, + attr: &syn::Attribute, + info: FieldInfo<'_>, + ) -> Result<(), SessionDiagnosticDeriveError> { + if !type_matches_path(&info.ty, &["rustc_span", "Span"]) { + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + let meta = attr.parse_meta()?; + + throw_span_err!( + attr.span().unwrap(), + &format!( + "the `#[{}{}]` attribute can only be applied to fields of type `Span`", + name, + match meta { + syn::Meta::Path(_) => "", + syn::Meta::NameValue(_) => " = ...", + syn::Meta::List(_) => "(...)", + } + ) + ); + } + + Ok(()) + } + + /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug and + /// `fluent_attr_identifier`. + fn add_subdiagnostic( + &self, + field_binding: &proc_macro2::Ident, + kind: &str, + fluent_attr_identifier: &str, + ) -> proc_macro2::TokenStream { + let diag = &self.diag; + + let slug = + self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug"); + let fn_name = format_ident!("span_{}", kind); + quote! { + #diag.#fn_name( + *#field_binding, + rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier) + ); } } |
