]> git.lizzy.rs Git - rust.git/commitdiff
Add checks to ensure that explanations have code examples using the error code and...
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Mon, 20 Apr 2020 12:35:15 +0000 (14:35 +0200)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Wed, 22 Apr 2020 13:10:07 +0000 (15:10 +0200)
src/tools/tidy/src/error_codes_check.rs

index 428c57d3ee82236ba3f0c707003ea9b883675080..243d41598f86c739dba3941f668a42e75e47f9f1 100644 (file)
     "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<String, bool>,
     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<String, bool>, path: &Path) {
+fn extract_error_codes(
+    f: &str,
+    error_codes: &mut HashMap<String, bool>,
+    path: &Path,
+    errors: &mut Vec<String>,
+) {
     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<String, bool>, 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<String, boo
 }
 
 pub fn check(path: &Path, bad: &mut bool) {
+    let mut errors = Vec::new();
     println!("Checking which error codes lack tests...");
     let mut error_codes: HashMap<String, bool> = 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();