@@ -15,21 +15,57 @@ const WHITELIST: &[&str] = &[
15
15
"E0727" , "E0729" ,
16
16
] ;
17
17
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
+
18
22
fn check_error_code_explanation (
19
23
f : & str ,
20
24
error_codes : & mut HashMap < String , bool > ,
21
25
err_code : String ,
22
- ) {
26
+ ) -> bool {
27
+ let mut invalid_compile_fail_format = false ;
28
+ let mut found_error_code = false ;
29
+
23
30
for line in f. lines ( ) {
24
31
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
+ }
28
41
} 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
+ }
31
46
}
32
47
}
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
33
69
}
34
70
35
71
macro_rules! some_or_continue {
@@ -41,7 +77,12 @@ macro_rules! some_or_continue {
41
77
} ;
42
78
}
43
79
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
+ ) {
45
86
let mut reached_no_explanation = false ;
46
87
47
88
for line in f. lines ( ) {
@@ -55,10 +96,26 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &
55
96
// Now we extract the tests from the markdown file!
56
97
let md = some_or_continue ! ( s. splitn( 2 , "include_str!(\" " ) . nth( 1 ) ) ;
57
98
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" ) ;
59
103
match read_to_string ( & path) {
60
104
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
+ }
62
119
}
63
120
Err ( e) => {
64
121
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
94
151
}
95
152
96
153
pub fn check ( path : & Path , bad : & mut bool ) {
154
+ let mut errors = Vec :: new ( ) ;
97
155
println ! ( "Checking which error codes lack tests..." ) ;
98
156
let mut error_codes: HashMap < String , bool > = HashMap :: new ( ) ;
99
157
super :: walk ( path, & mut |path| super :: filter_dirs ( path) , & mut |entry, contents| {
100
158
let file_name = entry. file_name ( ) ;
101
159
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 ) ;
103
161
} else if entry. path ( ) . extension ( ) == Some ( OsStr :: new ( "stderr" ) ) {
104
162
extract_error_codes_from_tests ( contents, & mut error_codes) ;
105
163
}
106
164
} ) ;
107
- println ! ( "Found {} error codes" , error_codes. len( ) ) ;
165
+ if errors. is_empty ( ) {
166
+ println ! ( "Found {} error codes" , error_codes. len( ) ) ;
108
167
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
+ }
113
172
}
114
173
}
115
174
errors. sort ( ) ;
0 commit comments