33
44use  std:: collections:: HashMap ; 
55use  std:: ffi:: OsStr ; 
6+ use  std:: fs:: read_to_string; 
7+ use  std:: io:: Read ; 
68use  std:: path:: Path ; 
79
810// A few of those error codes can't be tested but all the others can and *should* be tested! 
@@ -50,41 +52,69 @@ const WHITELIST: &[&str] = &[
5052    "E0729" , 
5153] ; 
5254
53- fn  extract_error_codes ( f :  & str ,  error_codes :  & mut  HashMap < String ,  bool > )  { 
55+ fn  check_error_code_explanation ( 
56+     f :  & str , 
57+     error_codes :  & mut  HashMap < String ,  bool > , 
58+     err_code :  String , 
59+ )  { 
60+     for  line in  f. lines ( )  { 
61+         let  s = line. trim ( ) ; 
62+         if  s. starts_with ( "```" )  && s. contains ( "compile_fail" )  && s. contains ( 'E' )  { 
63+             error_codes. insert ( err_code,  true ) ; 
64+             return ; 
65+         }  else  if  s. starts_with ( "#### Note: this error code is no longer emitted by the compiler" )  { 
66+             error_codes. get_mut ( & err_code) . map ( |x| * x = true ) ; 
67+             return ; 
68+         } 
69+     } 
70+ } 
71+ 
72+ macro_rules!  some_or_continue { 
73+     ( $e: expr)  => ( 
74+         match  $e { 
75+             Some ( e)  => e, 
76+             None  => continue , 
77+         } 
78+     ) ; 
79+ } 
80+ 
81+ fn  extract_error_codes ( f :  & str ,  error_codes :  & mut  HashMap < String ,  bool > ,  path :  & Path )  { 
5482    let  mut  reached_no_explanation = false ; 
55-     let  mut  last_error_code = None ; 
5683
5784    for  line in  f. lines ( )  { 
5885        let  s = line. trim ( ) ; 
59-         if  s. starts_with ( 'E' )  && s. ends_with ( ": r## \" ")  { 
86+         if  !reached_no_explanation &&  s. starts_with ( 'E' )  && s. contains ( "include_str!( \" ")  { 
6087            if  let  Some ( err_code)  = s. splitn ( 2 ,  ':' ) . next ( )  { 
6188                let  err_code = err_code. to_owned ( ) ; 
62-                 last_error_code = Some ( err_code. clone ( ) ) ; 
6389                if  !error_codes. contains_key ( & err_code)  { 
64-                     error_codes. insert ( err_code,  false ) ; 
90+                     error_codes. insert ( err_code. clone ( ) ,  false ) ; 
6591                } 
66-             } 
67-         }  else  if  s. starts_with ( "```" )  && s. contains ( "compile_fail" )  && s. contains ( 'E' )  { 
68-             if  let  Some ( err_code)  = s. splitn ( 2 ,  'E' ) . skip ( 1 ) . next ( )  { 
69-                 if  let  Some ( err_code)  = err_code. splitn ( 2 ,  ',' ) . next ( )  { 
70-                     let  nb = error_codes. entry ( format ! ( "E{}" ,  err_code) ) . or_insert ( false ) ; 
71-                     * nb = true ; 
92+                 // Now we extract the tests from the markdown file! 
93+                 let  md = some_or_continue ! ( s. splitn( 2 ,  "include_str!(\" " ) . skip( 1 ) . next( ) ) ; 
94+                 let  md_file_name = some_or_continue ! ( md. splitn( 2 ,  "\" )" ) . next( ) ) ; 
95+                 let  path = some_or_continue ! ( path. parent( ) ) . join ( md_file_name) ; 
96+                 match  read_to_string ( & path)  { 
97+                     Ok ( content)  => { 
98+                         check_error_code_explanation ( 
99+                             & content, 
100+                             error_codes, 
101+                             err_code, 
102+                         ) ; 
103+                     } 
104+                     Err ( e)  => { 
105+                         eprintln ! ( "Couldn't read `{}`: {}" ,  path. display( ) ,  e) ; 
106+                     } 
72107                } 
73108            } 
74-         }  else  if  s == ";"  { 
75-             reached_no_explanation = true ; 
76109        }  else  if  reached_no_explanation && s. starts_with ( 'E' )  { 
77110            if  let  Some ( err_code)  = s. splitn ( 2 ,  ',' ) . next ( )  { 
78111                let  err_code = err_code. to_owned ( ) ; 
79112                if  !error_codes. contains_key ( & err_code)  {  // this check should *never* fail! 
80113                    error_codes. insert ( err_code,  false ) ; 
81114                } 
82115            } 
83-         }  else  if  s. starts_with ( "#### Note: this error code is no longer emitted by the compiler" )  { 
84-             if  let  Some ( last)  = last_error_code { 
85-                 error_codes. get_mut ( & last) . map ( |x| * x = true ) ; 
86-             } 
87-             last_error_code = None ; 
116+         }  else  if  s == ";"  { 
117+             reached_no_explanation = true ; 
88118        } 
89119    } 
90120} 
@@ -111,7 +141,7 @@ pub fn check(path: &Path, bad: &mut bool) {
111141                & mut  |entry,  contents| { 
112142        let  file_name = entry. file_name ( ) ; 
113143        if  file_name == "error_codes.rs"  { 
114-             extract_error_codes ( contents,  & mut  error_codes) ; 
144+             extract_error_codes ( contents,  & mut  error_codes,  entry . path ( ) ) ; 
115145        }  else  if  entry. path ( ) . extension ( )  == Some ( OsStr :: new ( "stderr" ) )  { 
116146            extract_error_codes_from_tests ( contents,  & mut  error_codes) ; 
117147        } 
0 commit comments