Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a tidy check that checks whether the fluent slugs only appear once #121860

Merged
merged 2 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,6 @@ const_eval_intern_kind = {$kind ->
*[other] {""}
}

const_eval_invalid_align =
align has to be a power of 2

const_eval_invalid_align_details =
invalid align passed to `{$name}`: {$align} is {$err_kind ->
[not_power_of_two] not a power of 2
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_infer/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,6 @@ infer_more_targeted = {$has_param_name ->

infer_msl_introduces_static = introduces a `'static` lifetime requirement
infer_msl_unmet_req = because this has an unmet lifetime requirement
infer_need_type_info_in_coroutine =
type inside {$coroutine_kind ->
[async_block] `async` block
[async_closure] `async` closure
[async_fn] `async fn` body
*[coroutine] coroutine
} must be known in this context


infer_nothing = {""}

Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,6 @@ lint_suspicious_double_ref_clone =
lint_suspicious_double_ref_deref =
using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type

lint_trivial_untranslatable_diag = diagnostic with static strings only

lint_ty_qualified = usage of qualified `ty::{$ty}`
.suggestion = try importing it and using it unqualified

Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n

parse_invalid_interpolated_expression = invalid interpolated expression

parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
.label = invalid suffix `{$suffix}`

parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
.label = invalid suffix `{$suffix}`
.tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
Expand Down Expand Up @@ -609,7 +606,6 @@ parse_nonterminal_expected_item_keyword = expected an item keyword
parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`

parse_nonterminal_expected_statement = expected a statement
parse_not_supported = not supported

parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide

Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,6 @@ passes_export_name =
attribute should be applied to a free function, impl method or static
.label = not a free function, impl method or static

passes_expr_not_allowed_in_context =
{$expr} is not allowed in a `{$context}`

passes_extern_main =
the `main` function cannot be declared in an `extern` block

Expand Down Expand Up @@ -405,8 +402,6 @@ passes_lang_item_on_incorrect_target =
`{$name}` language item must be applied to a {$expected_target}
.label = attribute should be applied to a {$expected_target}, not a {$actual_target}

passes_layout =
layout error: {$layout_error}
passes_layout_abi =
abi: {$abi}
passes_layout_align =
Expand Down
58 changes: 52 additions & 6 deletions src/tools/tidy/src/fluent_alphabetical.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Checks that all Flunt files have messages in alphabetical order

use crate::walk::{filter_dirs, walk};
use std::collections::HashMap;
use std::{fs::OpenOptions, io::Write, path::Path};

use regex::Regex;
Expand All @@ -13,11 +14,27 @@ fn filter_fluent(path: &Path) -> bool {
if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
}

fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) {
fn check_alphabetic(
filename: &str,
fluent: &str,
bad: &mut bool,
all_defined_msgs: &mut HashMap<String, String>,
) {
let mut matches = MESSAGE.captures_iter(fluent).peekable();
while let Some(m) = matches.next() {
let name = m.get(1).unwrap();
if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
tidy_error!(
bad,
"{filename}: message `{}` is already defined in {}",
name.as_str(),
defined_filename,
);
}

all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());

if let Some(next) = matches.peek() {
let name = m.get(1).unwrap();
let next = next.get(1).unwrap();
if name.as_str() > next.as_str() {
tidy_error!(
Expand All @@ -34,13 +51,29 @@ run `./x.py test tidy --bless` to sort the file correctly",
}
}

fn sort_messages(fluent: &str) -> String {
fn sort_messages(
filename: &str,
fluent: &str,
bad: &mut bool,
all_defined_msgs: &mut HashMap<String, String>,
) -> String {
let mut chunks = vec![];
let mut cur = String::new();
for line in fluent.lines() {
if MESSAGE.is_match(line) {
if let Some(name) = MESSAGE.find(line) {
if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
tidy_error!(
bad,
"{filename}: message `{}` is already defined in {}",
name.as_str(),
defined_filename,
);
}

all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());
chunks.push(std::mem::take(&mut cur));
}

cur += line;
cur.push('\n');
}
Expand All @@ -53,20 +86,33 @@ fn sort_messages(fluent: &str) -> String {
}

pub fn check(path: &Path, bless: bool, bad: &mut bool) {
let mut all_defined_msgs = HashMap::new();
walk(
path,
|path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
&mut |ent, contents| {
if bless {
let sorted = sort_messages(contents);
let sorted = sort_messages(
ent.path().to_str().unwrap(),
contents,
bad,
&mut all_defined_msgs,
);
if sorted != contents {
let mut f =
OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap();
f.write(sorted.as_bytes()).unwrap();
}
} else {
check_alphabetic(ent.path().to_str().unwrap(), contents, bad);
check_alphabetic(
ent.path().to_str().unwrap(),
contents,
bad,
&mut all_defined_msgs,
);
}
},
);

crate::fluent_used::check(path, all_defined_msgs, bad);
}
43 changes: 43 additions & 0 deletions src/tools/tidy/src/fluent_used.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! Checks that all Fluent messages appear at least twice

use crate::walk::{filter_dirs, walk};
use regex::Regex;
use std::collections::HashMap;
use std::path::Path;

lazy_static::lazy_static! {
static ref WORD: Regex = Regex::new(r"\w+").unwrap();
}

fn filter_used_messages(
contents: &str,
msgs_not_appeared_yet: &mut HashMap<String, String>,
msgs_appeared_only_once: &mut HashMap<String, String>,
) {
// we don't just check messages never appear in Rust files,
// because messages can be used as parts of other fluent messages in Fluent files,
// so we do checking messages appear only once in all Rust and Fluent files.
let mut matches = WORD.find_iter(contents);
while let Some(name) = matches.next() {
if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
// if one msg appears for the first time,
// remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`.
msgs_appeared_only_once.insert(name, filename);
} else {
// if one msg appears for the second time,
// remove it from `msgs_appeared_only_once`.
msgs_appeared_only_once.remove(name.as_str());
}
}
}

pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, bad: &mut bool) {
let mut msgs_appear_only_once = HashMap::new();
walk(path, |path, _| filter_dirs(path), &mut |_, contents| {
filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once);
});

for (name, filename) in msgs_appear_only_once {
tidy_error!(bad, "{filename}: message `{}` is not used", name,);
}
}
1 change: 1 addition & 0 deletions src/tools/tidy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub mod ext_tool_checks;
pub mod extdeps;
pub mod features;
pub mod fluent_alphabetical;
mod fluent_used;
pub(crate) mod iter_header;
pub mod mir_opt_tests;
pub mod pal;
Expand Down
Loading