11
11
12
12
use std:: collections:: HashMap ;
13
13
use std:: fmt;
14
- use std:: fs:: { self , File } ;
15
- use std:: io:: prelude:: * ;
14
+ use std:: fs;
16
15
use std:: path:: Path ;
17
16
18
- use regex:: { Regex , escape } ;
17
+ use regex:: Regex ;
19
18
20
19
mod version;
21
20
use version:: Version ;
@@ -51,20 +50,48 @@ pub struct Feature {
51
50
52
51
pub type Features = HashMap < String , Feature > ;
53
52
54
- pub fn check ( path : & Path , bad : & mut bool , quiet : bool ) {
53
+ pub struct CollectedFeatures {
54
+ pub lib : Features ,
55
+ pub lang : Features ,
56
+ }
57
+
58
+ // Currently only used for unstable book generation
59
+ pub fn collect_lib_features ( base_src_path : & Path ) -> Features {
60
+ let mut lib_features = Features :: new ( ) ;
61
+
62
+ // This library feature is defined in the `compiler_builtins` crate, which
63
+ // has been moved out-of-tree. Now it can no longer be auto-discovered by
64
+ // `tidy`, because we need to filter out its (submodule) directory. Manually
65
+ // add it to the set of known library features so we can still generate docs.
66
+ lib_features. insert ( "compiler_builtins_lib" . to_owned ( ) , Feature {
67
+ level : Status :: Unstable ,
68
+ since : None ,
69
+ has_gate_test : false ,
70
+ tracking_issue : None ,
71
+ } ) ;
72
+
73
+ map_lib_features ( base_src_path,
74
+ & mut |res, _, _| {
75
+ if let Ok ( ( name, feature) ) = res {
76
+ lib_features. insert ( name. to_owned ( ) , feature) ;
77
+ }
78
+ } ) ;
79
+ lib_features
80
+ }
81
+
82
+ pub fn check ( path : & Path , bad : & mut bool , verbose : bool ) -> CollectedFeatures {
55
83
let mut features = collect_lang_features ( path, bad) ;
56
84
assert ! ( !features. is_empty( ) ) ;
57
85
58
86
let lib_features = get_and_check_lib_features ( path, bad, & features) ;
59
87
assert ! ( !lib_features. is_empty( ) ) ;
60
88
61
- let mut contents = String :: new ( ) ;
62
-
63
89
super :: walk_many ( & [ & path. join ( "test/ui" ) ,
64
90
& path. join ( "test/ui-fulldeps" ) ,
65
91
& path. join ( "test/compile-fail" ) ] ,
66
92
& mut |path| super :: filter_dirs ( path) ,
67
- & mut |file| {
93
+ & mut |entry, contents| {
94
+ let file = entry. path ( ) ;
68
95
let filename = file. file_name ( ) . unwrap ( ) . to_string_lossy ( ) ;
69
96
if !filename. ends_with ( ".rs" ) || filename == "features.rs" ||
70
97
filename == "diagnostic_list.rs" {
@@ -74,9 +101,6 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
74
101
let filen_underscore = filename. replace ( '-' , "_" ) . replace ( ".rs" , "" ) ;
75
102
let filename_is_gate_test = test_filen_gate ( & filen_underscore, & mut features) ;
76
103
77
- contents. truncate ( 0 ) ;
78
- t ! ( t!( File :: open( & file) , & file) . read_to_string( & mut contents) ) ;
79
-
80
104
for ( i, line) in contents. lines ( ) . enumerate ( ) {
81
105
let mut err = |msg : & str | {
82
106
tidy_error ! ( bad, "{}:{}: {}" , file. display( ) , i + 1 , msg) ;
@@ -130,21 +154,23 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
130
154
}
131
155
132
156
if * bad {
133
- return ;
134
- }
135
- if quiet {
136
- println ! ( "* {} features" , features. len( ) ) ;
137
- return ;
157
+ return CollectedFeatures { lib : lib_features, lang : features } ;
138
158
}
139
159
140
- let mut lines = Vec :: new ( ) ;
141
- lines. extend ( format_features ( & features, "lang" ) ) ;
142
- lines. extend ( format_features ( & lib_features, "lib" ) ) ;
160
+ if verbose {
161
+ let mut lines = Vec :: new ( ) ;
162
+ lines. extend ( format_features ( & features, "lang" ) ) ;
163
+ lines. extend ( format_features ( & lib_features, "lib" ) ) ;
143
164
144
- lines. sort ( ) ;
145
- for line in lines {
146
- println ! ( "* {}" , line) ;
165
+ lines. sort ( ) ;
166
+ for line in lines {
167
+ println ! ( "* {}" , line) ;
168
+ }
169
+ } else {
170
+ println ! ( "* {} features" , features. len( ) ) ;
147
171
}
172
+
173
+ CollectedFeatures { lib : lib_features, lang : features }
148
174
}
149
175
150
176
fn format_features < ' a > ( features : & ' a Features , family : & ' a str ) -> impl Iterator < Item = String > + ' a {
@@ -159,8 +185,19 @@ fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator
159
185
}
160
186
161
187
fn find_attr_val < ' a > ( line : & ' a str , attr : & str ) -> Option < & ' a str > {
162
- let r = Regex :: new ( & format ! ( r#"{}\s*=\s*"([^"]*)""# , escape( attr) ) )
163
- . expect ( "malformed regex for find_attr_val" ) ;
188
+ lazy_static:: lazy_static! {
189
+ static ref ISSUE : Regex = Regex :: new( r#"issue\s*=\s*"([^"]*)""# ) . unwrap( ) ;
190
+ static ref FEATURE : Regex = Regex :: new( r#"feature\s*=\s*"([^"]*)""# ) . unwrap( ) ;
191
+ static ref SINCE : Regex = Regex :: new( r#"since\s*=\s*"([^"]*)""# ) . unwrap( ) ;
192
+ }
193
+
194
+ let r = match attr {
195
+ "issue" => & * ISSUE ,
196
+ "feature" => & * FEATURE ,
197
+ "since" => & * SINCE ,
198
+ _ => unimplemented ! ( "{} not handled" , attr) ,
199
+ } ;
200
+
164
201
r. captures ( line)
165
202
. and_then ( |c| c. get ( 1 ) )
166
203
. map ( |m| m. as_str ( ) )
@@ -175,9 +212,11 @@ fn test_find_attr_val() {
175
212
}
176
213
177
214
fn test_filen_gate ( filen_underscore : & str , features : & mut Features ) -> bool {
178
- if filen_underscore. starts_with ( "feature_gate" ) {
215
+ let prefix = "feature_gate_" ;
216
+ if filen_underscore. starts_with ( prefix) {
179
217
for ( n, f) in features. iter_mut ( ) {
180
- if filen_underscore == format ! ( "feature_gate_{}" , n) {
218
+ // Equivalent to filen_underscore == format!("feature_gate_{}", n)
219
+ if & filen_underscore[ prefix. len ( ) ..] == n {
181
220
f. has_gate_test = true ;
182
221
return true ;
183
222
}
@@ -295,32 +334,6 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
295
334
. collect ( )
296
335
}
297
336
298
- pub fn collect_lib_features ( base_src_path : & Path ) -> Features {
299
- let mut lib_features = Features :: new ( ) ;
300
-
301
- // This library feature is defined in the `compiler_builtins` crate, which
302
- // has been moved out-of-tree. Now it can no longer be auto-discovered by
303
- // `tidy`, because we need to filter out its (submodule) directory. Manually
304
- // add it to the set of known library features so we can still generate docs.
305
- lib_features. insert ( "compiler_builtins_lib" . to_owned ( ) , Feature {
306
- level : Status :: Unstable ,
307
- since : None ,
308
- has_gate_test : false ,
309
- tracking_issue : None ,
310
- } ) ;
311
-
312
- map_lib_features ( base_src_path,
313
- & mut |res, _, _| {
314
- if let Ok ( ( name, feature) ) = res {
315
- if lib_features. contains_key ( name) {
316
- return ;
317
- }
318
- lib_features. insert ( name. to_owned ( ) , feature) ;
319
- }
320
- } ) ;
321
- lib_features
322
- }
323
-
324
337
fn get_and_check_lib_features ( base_src_path : & Path ,
325
338
bad : & mut bool ,
326
339
lang_features : & Features ) -> Features {
@@ -355,20 +368,25 @@ fn get_and_check_lib_features(base_src_path: &Path,
355
368
356
369
fn map_lib_features ( base_src_path : & Path ,
357
370
mf : & mut dyn FnMut ( Result < ( & str , Feature ) , & str > , & Path , usize ) ) {
358
- let mut contents = String :: new ( ) ;
359
371
super :: walk ( base_src_path,
360
372
& mut |path| super :: filter_dirs ( path) || path. ends_with ( "src/test" ) ,
361
- & mut |file| {
373
+ & mut |entry, contents| {
374
+ let file = entry. path ( ) ;
362
375
let filename = file. file_name ( ) . unwrap ( ) . to_string_lossy ( ) ;
363
376
if !filename. ends_with ( ".rs" ) || filename == "features.rs" ||
364
377
filename == "diagnostic_list.rs" {
365
378
return ;
366
379
}
367
380
368
- contents. truncate ( 0 ) ;
369
- t ! ( t!( File :: open( & file) , & file) . read_to_string( & mut contents) ) ;
381
+ // This is an early exit -- all the attributes we're concerned with must contain this:
382
+ // * rustc_const_unstable(
383
+ // * unstable(
384
+ // * stable(
385
+ if !contents. contains ( "stable(" ) {
386
+ return ;
387
+ }
370
388
371
- let mut becoming_feature: Option < ( String , Feature ) > = None ;
389
+ let mut becoming_feature: Option < ( & str , Feature ) > = None ;
372
390
for ( i, line) in contents. lines ( ) . enumerate ( ) {
373
391
macro_rules! err {
374
392
( $msg: expr) => { {
@@ -447,7 +465,7 @@ fn map_lib_features(base_src_path: &Path,
447
465
if line. contains ( ']' ) {
448
466
mf ( Ok ( ( feature_name, feature) ) , file, i + 1 ) ;
449
467
} else {
450
- becoming_feature = Some ( ( feature_name. to_owned ( ) , feature) ) ;
468
+ becoming_feature = Some ( ( feature_name, feature) ) ;
451
469
}
452
470
}
453
471
} ) ;
0 commit comments