From 5c8f50952bb50e0e37b16ca4cd14c08c8e56a449 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Apr 2020 14:35:15 +0200 Subject: [PATCH] Add checks to ensure that explanations have code examples using the error code and also that 'compile_fail' isn't mispelled --- src/tools/tidy/src/error_codes_check.rs | 89 ++++++++++++++++++++----- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 428c57d3ee8..243d41598f8 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -15,21 +15,57 @@ "E0727", "E0729", ]; +// Some error codes don't have any tests apparently... +const IGNORE_EXPLANATION_CHECK: &[&str] = + &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750", "E0751"]; + fn check_error_code_explanation( f: &str, error_codes: &mut HashMap, err_code: String, -) { +) -> bool { + let mut invalid_compile_fail_format = false; + let mut found_error_code = false; + for line in f.lines() { let s = line.trim(); - if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') { - error_codes.insert(err_code, true); - return; + if s.starts_with("```") { + if s.contains("compile_fail") && s.contains('E') { + if !found_error_code { + error_codes.insert(err_code.clone(), true); + found_error_code = true; + } + } else if s.contains("compile-fail") { + invalid_compile_fail_format = true; + } } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") { - error_codes.get_mut(&err_code).map(|x| *x = true); - return; + if !found_error_code { + error_codes.get_mut(&err_code).map(|x| *x = true); + found_error_code = true; + } } } + invalid_compile_fail_format +} + +fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &String) -> bool { + let mut can_be_ignored = false; + + for line in f.lines() { + let s = line.trim(); + if s.starts_with("#### Note: this error code is no longer emitted by the compiler") { + return true; + } + if s.starts_with("```") { + if s.contains("compile_fail") && s.contains(err_code) { + return true; + } else if s.contains("(") { + // It's very likely that we can't actually make it fail compilation... + can_be_ignored = true; + } + } + } + can_be_ignored } macro_rules! some_or_continue { @@ -41,7 +77,12 @@ macro_rules! some_or_continue { }; } -fn extract_error_codes(f: &str, error_codes: &mut HashMap, path: &Path) { +fn extract_error_codes( + f: &str, + error_codes: &mut HashMap, + path: &Path, + errors: &mut Vec, +) { let mut reached_no_explanation = false; for line in f.lines() { @@ -55,10 +96,26 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap, path: & // Now we extract the tests from the markdown file! let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1)); let md_file_name = some_or_continue!(md.splitn(2, "\")").next()); - let path = some_or_continue!(path.parent()).join(md_file_name); + let path = some_or_continue!(path.parent()) + .join(md_file_name) + .canonicalize() + .expect("failed to canonicalize error explanation file path"); match read_to_string(&path) { Ok(content) => { - check_error_code_explanation(&content, error_codes, err_code); + if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) + && !check_if_error_code_is_test_in_explanation(&content, &err_code) + { + errors.push(format!( + "`{}` doesn't use its own error code in compile_fail example", + path.display(), + )); + } + if check_error_code_explanation(&content, error_codes, err_code) { + errors.push(format!( + "`{}` uses invalid tag `compile-fail` instead of `compile_fail`", + path.display(), + )); + } } Err(e) => { eprintln!("Couldn't read `{}`: {}", path.display(), e); @@ -94,22 +151,24 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap = HashMap::new(); super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| { let file_name = entry.file_name(); if file_name == "error_codes.rs" { - extract_error_codes(contents, &mut error_codes, entry.path()); + extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors); } else if entry.path().extension() == Some(OsStr::new("stderr")) { extract_error_codes_from_tests(contents, &mut error_codes); } }); - println!("Found {} error codes", error_codes.len()); + if errors.is_empty() { + println!("Found {} error codes", error_codes.len()); - let mut errors = Vec::new(); - for (err_code, nb) in &error_codes { - if !*nb && !WHITELIST.contains(&err_code.as_str()) { - errors.push(format!("Error code {} needs to have at least one UI test!", err_code)); + for (err_code, nb) in &error_codes { + if !*nb && !WHITELIST.contains(&err_code.as_str()) { + errors.push(format!("Error code {} needs to have at least one UI test!", err_code)); + } } } errors.sort(); -- 2.44.0