Skip to content

Commit ed707a1

Browse files
committed
Detect references to non-existant messages in Fluent resources
1 parent 5e37043 commit ed707a1

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

compiler/rustc_macros/src/diagnostics/fluent.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use annotate_snippets::{
44
};
55
use fluent_bundle::{FluentBundle, FluentError, FluentResource};
66
use fluent_syntax::{
7-
ast::{Attribute, Entry, Identifier, Message},
7+
ast::{
8+
Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern,
9+
PatternElement,
10+
},
811
parser::ParserError,
912
};
1013
use proc_macro::{Diagnostic, Level, Span};
@@ -185,9 +188,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
185188
};
186189

187190
let mut constants = TokenStream::new();
191+
let mut messagerefs = Vec::new();
188192
for entry in resource.entries() {
189193
let span = res.krate.span();
190-
if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
194+
if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) =
195+
entry
196+
{
191197
let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
192198

193199
if name.contains('-') {
@@ -200,6 +206,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
200206
.emit();
201207
}
202208

209+
if let Some(Pattern { elements }) = value {
210+
for elt in elements {
211+
if let PatternElement::Placeable {
212+
expression:
213+
Expression::Inline(InlineExpression::MessageReference { id, .. }),
214+
} = elt
215+
{
216+
messagerefs.push((id.name, *name));
217+
}
218+
}
219+
}
220+
203221
// Require that the message name starts with the crate name
204222
// `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
205223
// `const_eval_baz` (in `const_eval.ftl`)
@@ -258,6 +276,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
258276
}
259277
}
260278

279+
for (mref, name) in messagerefs.into_iter() {
280+
if !previous_defns.contains_key(mref) {
281+
Diagnostic::spanned(
282+
path_span,
283+
Level::Error,
284+
format!("referenced message `{mref}` does not exist (in message `{name}`)"),
285+
)
286+
.help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)"))
287+
.emit();
288+
}
289+
}
290+
261291
if let Err(errs) = bundle.add_resource(resource) {
262292
for e in errs {
263293
match e {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
missing_message_ref = {message}

tests/ui-fulldeps/fluent-messages/test.rs

+9
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,12 @@ mod missing_crate_name {
9696

9797
use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, test_crate_foo, with_hyphens};
9898
}
99+
100+
mod missing_message_ref {
101+
use super::fluent_messages;
102+
103+
fluent_messages! {
104+
missing => "./missing-message-ref.ftl"
105+
//~^ ERROR referenced message `message` does not exist
106+
}
107+
}

tests/ui-fulldeps/fluent-messages/test.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ LL | test_crate => "./missing-crate-name.ftl",
9393
|
9494
= help: replace any '-'s with '_'s
9595

96-
error: aborting due to 10 previous errors
96+
error: referenced message `message` does not exist (in message `missing_message_ref`)
97+
--> $DIR/test.rs:104:20
98+
|
99+
LL | missing => "./missing-message-ref.ftl"
100+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
101+
|
102+
= help: you may have meant to use a variable reference (`{$message}`)
103+
104+
error: aborting due to 11 previous errors
97105

98106
For more information about this error, try `rustc --explain E0428`.

0 commit comments

Comments
 (0)