Skip to content

Commit ea681ef

Browse files
Add a tidy rule to make sure that diagnostics don't end in periods
1 parent c1b336c commit ea681ef

File tree

4 files changed

+87
-0
lines changed

4 files changed

+87
-0
lines changed

src/tools/tidy/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ ignore = "0.4.18"
1313
semver = "1.0"
1414
termcolor = "1.1.3"
1515
rustc-hash = "1.1.0"
16+
fluent-syntax = "0.11.1"
1617

1718
[[bin]]
1819
name = "rust-tidy"

src/tools/tidy/src/fluent_period.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//! Checks that no Fluent messages or attributes end in periods (except ellipses)
2+
3+
use fluent_syntax::ast::{Entry, PatternElement};
4+
5+
use crate::walk::{filter_dirs, walk};
6+
use std::path::Path;
7+
8+
fn filter_fluent(path: &Path) -> bool {
9+
if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
10+
}
11+
12+
/// Messages allowed to have `.` at their end.
13+
///
14+
/// These should probably be reworked eventually.
15+
const ALLOWLIST: &[&str] = &[
16+
"const_eval_long_running",
17+
"const_eval_validation_failure_note",
18+
"driver_impl_ice",
19+
"incremental_corrupt_file",
20+
"mir_build_pointer_pattern",
21+
];
22+
23+
fn check_period(filename: &str, contents: &str, bad: &mut bool) {
24+
if filename.contains("codegen") {
25+
// FIXME: Too many codegen messages have periods right now...
26+
return;
27+
}
28+
29+
let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
30+
for entry in &parse.body {
31+
if let Entry::Message(m) = entry {
32+
if ALLOWLIST.contains(&m.id.name) {
33+
continue;
34+
}
35+
36+
if let Some(pat) = &m.value {
37+
if let Some(PatternElement::TextElement { value }) = pat.elements.last() {
38+
// We don't care about ellipses.
39+
if value.ends_with(".") && !value.ends_with("...") {
40+
let ll = find_line(contents, *value);
41+
let name = m.id.name;
42+
tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period");
43+
}
44+
}
45+
}
46+
47+
for attr in &m.attributes {
48+
// Teach notes usually have long messages.
49+
if attr.id.name == "teach_note" {
50+
continue;
51+
}
52+
53+
if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() {
54+
if value.ends_with(".") && !value.ends_with("...") {
55+
let ll = find_line(contents, *value);
56+
let name = attr.id.name;
57+
tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period");
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
65+
/// Evil cursed bad hack. Requires that `value` be a substr (in memory) of `contents`.
66+
fn find_line(haystack: &str, needle: &str) -> usize {
67+
for (ll, line) in haystack.lines().enumerate() {
68+
if line.as_ptr() > needle.as_ptr() {
69+
return ll;
70+
}
71+
}
72+
73+
1
74+
}
75+
76+
pub fn check(path: &Path, bad: &mut bool) {
77+
walk(
78+
path,
79+
|path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
80+
&mut |ent, contents| {
81+
check_period(ent.path().to_str().unwrap(), contents, bad);
82+
},
83+
);
84+
}

src/tools/tidy/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub mod ext_tool_checks;
7272
pub mod extdeps;
7373
pub mod features;
7474
pub mod fluent_alphabetical;
75+
pub mod fluent_period;
7576
mod fluent_used;
7677
pub(crate) mod iter_header;
7778
pub mod known_bug;

src/tools/tidy/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ fn main() {
115115
// Checks that only make sense for the compiler.
116116
check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
117117
check!(fluent_alphabetical, &compiler_path, bless);
118+
check!(fluent_period, &compiler_path);
118119
check!(target_policy, &root_path);
119120

120121
// Checks that only make sense for the std libs.

0 commit comments

Comments
 (0)