@@ -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+ 
1822fn  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
3571macro_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
96153pub  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