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::walk::{filter_dirs, walk};
7
8fn filter_used_messages(
9    contents: &str,
10    msgs_not_appeared_yet: &mut HashMap<String, String>,
11    msgs_appeared_only_once: &mut HashMap<String, String>,
12) {
13    // we don't just check messages never appear in Rust files,
14    // because messages can be used as parts of other fluent messages in Fluent files,
15    // so we do checking messages appear only once in all Rust and Fluent files.
16    let mut matches = static_regex!(r"\w+").find_iter(contents);
17    while let Some(name) = matches.next() {
18        if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
19            // if one msg appears for the first time,
20            // remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`.
21            msgs_appeared_only_once.insert(name, filename);
22        } else {
23            // if one msg appears for the second time,
24            // remove it from `msgs_appeared_only_once`.
25            msgs_appeared_only_once.remove(name.as_str());
26        }
27    }
28}
29
30pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, bad: &mut bool) {
31    let mut msgs_appear_only_once = HashMap::new();
32    walk(path, |path, _| filter_dirs(path), &mut |_, contents| {
33        filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once);
34    });
35
36    for (name, filename) in msgs_appear_only_once {
37        tidy_error!(bad, "{filename}: message `{}` is not used", name,);
38    }
39}