errors: simplify referring to fluent attributes
To render the message of a Fluent attribute, the identifier of the Fluent message must be known. `DiagnosticMessage::FluentIdentifier` contains both the message's identifier and optionally the identifier of an attribute. Generated constants for each attribute would therefore need to be named uniquely (amongst all error messages) or be able to refer to only the attribute identifier which will be combined with a message identifier later. In this commit, the latter strategy is implemented as part of the `Diagnostic` type's functions for adding subdiagnostics of various kinds. Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
855fc022fe
commit
f669b78ffc
13 changed files with 190 additions and 150 deletions
|
@ -126,14 +126,14 @@ impl<'a> SessionDiagnosticDerive<'a> {
|
|||
(Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
|
||||
quote! {
|
||||
let mut #diag = #sess.struct_err(
|
||||
rustc_errors::DiagnosticMessage::fluent(#slug),
|
||||
rustc_errors::DiagnosticMessage::new(#slug),
|
||||
);
|
||||
}
|
||||
}
|
||||
(Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
|
||||
quote! {
|
||||
let mut #diag = #sess.struct_warn(
|
||||
rustc_errors::DiagnosticMessage::fluent(#slug),
|
||||
rustc_errors::DiagnosticMessage::new(#slug),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -254,21 +254,6 @@ impl SessionDiagnosticDeriveBuilder {
|
|||
|
||||
if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | 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 {
|
||||
Meta::Path(_) => "",
|
||||
Meta::NameValue(_) => " = ...",
|
||||
_ => unreachable!(),
|
||||
}
|
||||
)
|
||||
),
|
||||
};
|
||||
let id = match meta {
|
||||
Meta::Path(..) => quote! { #name },
|
||||
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
|
||||
|
@ -279,7 +264,7 @@ impl SessionDiagnosticDeriveBuilder {
|
|||
let fn_name = proc_macro2::Ident::new(name, attr.span());
|
||||
|
||||
return Ok(quote! {
|
||||
#diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id));
|
||||
#diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -525,13 +510,8 @@ impl SessionDiagnosticDeriveBuilder {
|
|||
|
||||
let method = format_ident!("span_{}", name);
|
||||
|
||||
let slug = self
|
||||
.slug
|
||||
.as_ref()
|
||||
.map(|(slug, _)| slug.as_str())
|
||||
.unwrap_or_else(|| "missing-slug");
|
||||
let msg = msg.as_deref().unwrap_or("suggestion");
|
||||
let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) };
|
||||
let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) };
|
||||
let code = code.unwrap_or_else(|| quote! { String::new() });
|
||||
|
||||
Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
|
||||
|
@ -549,14 +529,11 @@ impl SessionDiagnosticDeriveBuilder {
|
|||
fluent_attr_identifier: &str,
|
||||
) -> 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)
|
||||
rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -565,9 +542,8 @@ impl SessionDiagnosticDeriveBuilder {
|
|||
/// and `fluent_attr_identifier`.
|
||||
fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream {
|
||||
let diag = &self.diag;
|
||||
let slug = self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or("missing-slug");
|
||||
quote! {
|
||||
#diag.#kind(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier));
|
||||
#diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use proc_macro::{Diagnostic, Level, Span};
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
fs::File,
|
||||
io::Read,
|
||||
path::{Path, PathBuf},
|
||||
|
@ -100,6 +100,10 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
|||
let ident_span = res.ident.span().unwrap();
|
||||
let path_span = res.resource.span().unwrap();
|
||||
|
||||
// Set of Fluent attribute names already output, to avoid duplicate type errors - any given
|
||||
// constant created for a given attribute is the same.
|
||||
let mut previous_attrs = HashSet::new();
|
||||
|
||||
let relative_ftl_path = res.resource.value();
|
||||
let absolute_ftl_path =
|
||||
invocation_relative_path_to_absolute(ident_span, &relative_ftl_path);
|
||||
|
@ -199,13 +203,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
|||
});
|
||||
|
||||
for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
|
||||
let attr_snake_name = attr_name.replace("-", "_");
|
||||
let snake_name = Ident::new(&format!("{snake_name}_{attr_snake_name}"), span);
|
||||
let snake_name = Ident::new(&attr_name.replace("-", "_"), span);
|
||||
if !previous_attrs.insert(snake_name.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
constants.extend(quote! {
|
||||
pub const #snake_name: crate::DiagnosticMessage =
|
||||
crate::DiagnosticMessage::FluentIdentifier(
|
||||
std::borrow::Cow::Borrowed(#name),
|
||||
Some(std::borrow::Cow::Borrowed(#attr_name))
|
||||
pub const #snake_name: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(
|
||||
std::borrow::Cow::Borrowed(#attr_name)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -397,7 +397,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
|
|||
|
||||
let diag = &self.diag;
|
||||
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
|
||||
let message = quote! { rustc_errors::DiagnosticMessage::fluent(#slug) };
|
||||
let message = quote! { rustc_errors::SubdiagnosticMessage::message(#slug) };
|
||||
let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
|
||||
if let Some(span) = span_field {
|
||||
quote! { #diag.#name(#span, #message, #code, #applicability); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue