tidy/
fluent_used.rs

1//! Checks that all Fluent messages appear at least twice
2
3use std::collections::HashMap;
4use std::path::Path;
5
6use crate::diagnostics::{CheckId, DiagCtx};
7use crate::walk::{filter_dirs, walk};
8
9fn filter_used_messages(
10    contents: &str,
11    msgs_not_appeared_yet: &mut HashMap<String, String>,
12    msgs_appeared_only_once: &mut HashMap<String, String>,
13) {
14    // we don't just check messages never appear in Rust files,
15    // because messages can be used as parts of other fluent messages in Fluent files,
16    // so we check messages appear only once in all Rust and Fluent files.
17    let matches = static_regex!(r"\w+").find_iter(contents);
18    for name in matches {
19        if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
20            // if one msg appears for the first time,
21            // remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`.
22            msgs_appeared_only_once.insert(name, filename);
23        } else {
24            // if one msg appears for the second time,
25            // remove it from `msgs_appeared_only_once`.
26            msgs_appeared_only_once.remove(name.as_str());
27        }
28    }
29}
30
31pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, diag_ctx: DiagCtx) {
32    let mut check = diag_ctx.start_check(CheckId::new("fluent_used").path(path));
33
34    let mut msgs_appear_only_once = HashMap::new();
35    walk(path, |path, _| filter_dirs(path), &mut |_, contents| {
36        filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once);
37    });
38
39    for (name, filename) in msgs_appear_only_once {
40        check.error(format!("{filename}: message `{name}` is not used"));
41    }
42}