about summary refs log tree commit diff
path: root/compiler/rustc_fluent_macro
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2023-05-05 21:26:42 +0100
committerclubby789 <jamie@hill-daniel.co.uk>2023-05-26 10:41:36 +0000
commit9b5574f028c75d794b51c96ff6471ddf756f329b (patch)
treed57f45ebda8ac979c9e83b43963a0877cec544b6 /compiler/rustc_fluent_macro
parentbe72f2587c91579406117f99fa332383d66b7dcd (diff)
downloadrust-9b5574f028c75d794b51c96ff6471ddf756f329b.tar.gz
rust-9b5574f028c75d794b51c96ff6471ddf756f329b.zip
Validate fluent variable references with `debug_assertions`
Diffstat (limited to 'compiler/rustc_fluent_macro')
-rw-r--r--compiler/rustc_fluent_macro/src/fluent.rs45
1 files changed, 42 insertions, 3 deletions
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 9dffc9a7645..b1c83e0dedc 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -179,7 +179,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
     let mut previous_defns = HashMap::new();
     let mut message_refs = Vec::new();
     for entry in resource.entries() {
-        if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) = entry {
+        if let Entry::Message(msg) = entry {
+            let Message { id: Identifier { name }, attributes, value, .. } = msg;
             let _ = previous_defns.entry(name.to_string()).or_insert(resource_span);
             if name.contains('-') {
                 Diagnostic::spanned(
@@ -229,9 +230,10 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                 continue;
             }
 
-            let msg = format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
+            let docstr =
+                format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
             constants.extend(quote! {
-                #[doc = #msg]
+                #[doc = #docstr]
                 pub const #snake_name: crate::DiagnosticMessage =
                     crate::DiagnosticMessage::FluentIdentifier(
                         std::borrow::Cow::Borrowed(#name),
@@ -269,6 +271,17 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                         );
                 });
             }
+            #[cfg(debug_assertions)]
+            {
+                // Record variables referenced by these messages so we can produce
+                // tests in the derive diagnostics to validate them.
+                let ident = quote::format_ident!("{snake_name}_refs");
+                let vrefs = variable_references(msg);
+                constants.extend(quote! {
+                    #[cfg(test)]
+                    pub const #ident: &[&str] = &[#(#vrefs),*];
+                })
+            }
         }
     }
 
@@ -334,3 +347,29 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
     }
     .into()
 }
+
+#[cfg(debug_assertions)]
+fn variable_references<'a>(msg: &Message<&'a str>) -> Vec<&'a str> {
+    let mut refs = vec![];
+    if let Some(Pattern { elements }) = &msg.value {
+        for elt in elements {
+            if let PatternElement::Placeable {
+                expression: Expression::Inline(InlineExpression::VariableReference { id }),
+            } = elt
+            {
+                refs.push(id.name);
+            }
+        }
+    }
+    for attr in &msg.attributes {
+        for elt in &attr.value.elements {
+            if let PatternElement::Placeable {
+                expression: Expression::Inline(InlineExpression::VariableReference { id }),
+            } = elt
+            {
+                refs.push(id.name);
+            }
+        }
+    }
+    refs
+}