Skip to content

Commit 5c8f509

Browse files
Add checks to ensure that explanations have code examples using the error code and also that 'compile_fail' isn't mispelled
1 parent 2dc5b60 commit 5c8f509

File tree

1 file changed

+74
-15
lines changed

1 file changed

+74
-15
lines changed

src/tools/tidy/src/error_codes_check.rs

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,57 @@ const WHITELIST: &[&str] = &[
1515
"E0727", "E0729",
1616
];
1717

18+
// Some error codes don't have any tests apparently...
19+
const IGNORE_EXPLANATION_CHECK: &[&str] =
20+
&["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750", "E0751"];
21+
1822
fn check_error_code_explanation(
1923
f: &str,
2024
error_codes: &mut HashMap<String, bool>,
2125
err_code: String,
22-
) {
26+
) -> bool {
27+
let mut invalid_compile_fail_format = false;
28+
let mut found_error_code = false;
29+
2330
for line in f.lines() {
2431
let s = line.trim();
25-
if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') {
26-
error_codes.insert(err_code, true);
27-
return;
32+
if s.starts_with("```") {
33+
if s.contains("compile_fail") && s.contains('E') {
34+
if !found_error_code {
35+
error_codes.insert(err_code.clone(), true);
36+
found_error_code = true;
37+
}
38+
} else if s.contains("compile-fail") {
39+
invalid_compile_fail_format = true;
40+
}
2841
} else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
29-
error_codes.get_mut(&err_code).map(|x| *x = true);
30-
return;
42+
if !found_error_code {
43+
error_codes.get_mut(&err_code).map(|x| *x = true);
44+
found_error_code = true;
45+
}
3146
}
3247
}
48+
invalid_compile_fail_format
49+
}
50+
51+
fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &String) -> bool {
52+
let mut can_be_ignored = false;
53+
54+
for line in f.lines() {
55+
let s = line.trim();
56+
if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
57+
return true;
58+
}
59+
if s.starts_with("```") {
60+
if s.contains("compile_fail") && s.contains(err_code) {
61+
return true;
62+
} else if s.contains("(") {
63+
// It's very likely that we can't actually make it fail compilation...
64+
can_be_ignored = true;
65+
}
66+
}
67+
}
68+
can_be_ignored
3369
}
3470

3571
macro_rules! some_or_continue {
@@ -41,7 +77,12 @@ macro_rules! some_or_continue {
4177
};
4278
}
4379

44-
fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &Path) {
80+
fn extract_error_codes(
81+
f: &str,
82+
error_codes: &mut HashMap<String, bool>,
83+
path: &Path,
84+
errors: &mut Vec<String>,
85+
) {
4586
let mut reached_no_explanation = false;
4687

4788
for line in f.lines() {
@@ -55,10 +96,26 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &
5596
// Now we extract the tests from the markdown file!
5697
let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1));
5798
let md_file_name = some_or_continue!(md.splitn(2, "\")").next());
58-
let path = some_or_continue!(path.parent()).join(md_file_name);
99+
let path = some_or_continue!(path.parent())
100+
.join(md_file_name)
101+
.canonicalize()
102+
.expect("failed to canonicalize error explanation file path");
59103
match read_to_string(&path) {
60104
Ok(content) => {
61-
check_error_code_explanation(&content, error_codes, err_code);
105+
if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
106+
&& !check_if_error_code_is_test_in_explanation(&content, &err_code)
107+
{
108+
errors.push(format!(
109+
"`{}` doesn't use its own error code in compile_fail example",
110+
path.display(),
111+
));
112+
}
113+
if check_error_code_explanation(&content, error_codes, err_code) {
114+
errors.push(format!(
115+
"`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
116+
path.display(),
117+
));
118+
}
62119
}
63120
Err(e) => {
64121
eprintln!("Couldn't read `{}`: {}", path.display(), e);
@@ -94,22 +151,24 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, boo
94151
}
95152

96153
pub fn check(path: &Path, bad: &mut bool) {
154+
let mut errors = Vec::new();
97155
println!("Checking which error codes lack tests...");
98156
let mut error_codes: HashMap<String, bool> = HashMap::new();
99157
super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
100158
let file_name = entry.file_name();
101159
if file_name == "error_codes.rs" {
102-
extract_error_codes(contents, &mut error_codes, entry.path());
160+
extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
103161
} else if entry.path().extension() == Some(OsStr::new("stderr")) {
104162
extract_error_codes_from_tests(contents, &mut error_codes);
105163
}
106164
});
107-
println!("Found {} error codes", error_codes.len());
165+
if errors.is_empty() {
166+
println!("Found {} error codes", error_codes.len());
108167

109-
let mut errors = Vec::new();
110-
for (err_code, nb) in &error_codes {
111-
if !*nb && !WHITELIST.contains(&err_code.as_str()) {
112-
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
168+
for (err_code, nb) in &error_codes {
169+
if !*nb && !WHITELIST.contains(&err_code.as_str()) {
170+
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
171+
}
113172
}
114173
}
115174
errors.sort();

0 commit comments

Comments
 (0)