about summary refs log tree commit diff
path: root/compiler/rustc_macros/src/diagnostics
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2023-01-19 23:48:08 +0000
committerclubby789 <jamie@hill-daniel.co.uk>2023-01-27 11:27:22 +0000
commited707a106cac7393db3b59d85b8b065d09840c61 (patch)
tree09494db58a72442679c02b53d692ceaccfc288b8 /compiler/rustc_macros/src/diagnostics
parent5e37043d63bfe2f3be8fa5a05b07d6c0dad5775d (diff)
Detect references to non-existant messages in Fluent resources
Diffstat (limited to 'compiler/rustc_macros/src/diagnostics')
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs34
1 files changed, 32 insertions, 2 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index 32338f9dfc5..08098c9bb2a 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -4,7 +4,10 @@ use annotate_snippets::{
 };
 use fluent_bundle::{FluentBundle, FluentError, FluentResource};
 use fluent_syntax::{
-    ast::{Attribute, Entry, Identifier, Message},
+    ast::{
+        Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern,
+        PatternElement,
+    },
     parser::ParserError,
 };
 use proc_macro::{Diagnostic, Level, Span};
@@ -185,9 +188,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
         };
 
         let mut constants = TokenStream::new();
+        let mut messagerefs = Vec::new();
         for entry in resource.entries() {
             let span = res.krate.span();
-            if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
+            if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) =
+                entry
+            {
                 let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
 
                 if name.contains('-') {
@@ -200,6 +206,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                     .emit();
                 }
 
+                if let Some(Pattern { elements }) = value {
+                    for elt in elements {
+                        if let PatternElement::Placeable {
+                            expression:
+                                Expression::Inline(InlineExpression::MessageReference { id, .. }),
+                        } = elt
+                        {
+                            messagerefs.push((id.name, *name));
+                        }
+                    }
+                }
+
                 // Require that the message name starts with the crate name
                 // `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
                 // `const_eval_baz` (in `const_eval.ftl`)
@@ -258,6 +276,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
             }
         }
 
+        for (mref, name) in messagerefs.into_iter() {
+            if !previous_defns.contains_key(mref) {
+                Diagnostic::spanned(
+                    path_span,
+                    Level::Error,
+                    format!("referenced message `{mref}` does not exist (in message `{name}`)"),
+                )
+                .help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)"))
+                .emit();
+            }
+        }
+
         if let Err(errs) = bundle.add_resource(resource) {
             for e in errs {
                 match e {