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