Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit de7c4e4

Browse files
committedJun 23, 2019
Auto merge of #62037 - Mark-Simulacrum:tidy-fast, r=eddyb
Speed up tidy master: Time (mean ± σ): 3.478 s ± 0.033 s [User: 3.298 s, System: 0.178 s] Range (min … max): 3.425 s … 3.525 s 10 runs This PR: Time (mean ± σ): 1.098 s ± 0.006 s [User: 783.7 ms, System: 310.2 ms] Range (min … max): 1.092 s … 1.113 s 10 runs Alleviates #59884. For the most part each commit stands on its own. Timings are on warm filesystem cache. r? @eddyb
2 parents 2cd5ed4 + 777951c commit de7c4e4

File tree

13 files changed

+173
-146
lines changed

13 files changed

+173
-146
lines changed
 

‎Cargo.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3801,9 +3801,11 @@ dependencies = [
38013801
name = "tidy"
38023802
version = "0.1.0"
38033803
dependencies = [
3804+
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
38043805
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
38053806
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
38063807
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
3808+
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
38073809
]
38083810

38093811
[[package]]

‎src/bootstrap/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,8 +709,8 @@ impl Step for Tidy {
709709
if !builder.config.vendor {
710710
cmd.arg("--no-vendor");
711711
}
712-
if !builder.config.verbose_tests {
713-
cmd.arg("--quiet");
712+
if builder.is_verbose() {
713+
cmd.arg("--verbose");
714714
}
715715

716716
let _folder = builder.fold_output(|| "tidy");

‎src/tools/tidy/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ edition = "2018"
88
regex = "1"
99
serde = { version = "1.0.8", features = ["derive"] }
1010
serde_json = "1.0.2"
11+
lazy_static = "1"
12+
walkdir = "2"

‎src/tools/tidy/src/bins.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@ pub fn check(path: &Path, bad: &mut bool) {
2525
}
2626
}
2727

28-
super::walk(path,
28+
super::walk_no_read(path,
2929
&mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
30-
&mut |file| {
30+
&mut |entry| {
31+
let file = entry.path();
3132
let filename = file.file_name().unwrap().to_string_lossy();
3233
let extensions = [".py", ".sh"];
3334
if extensions.iter().any(|e| filename.ends_with(e)) {
3435
return;
3536
}
3637

37-
let metadata = t!(fs::symlink_metadata(&file), &file);
38+
let metadata = t!(entry.metadata(), file);
3839
if metadata.mode() & 0o111 != 0 {
3940
let rel_path = file.strip_prefix(path).unwrap();
4041
let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");

‎src/tools/tidy/src/errors.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,19 @@
44
//! statistics about the error codes.
55
66
use std::collections::HashMap;
7-
use std::fs::File;
8-
use std::io::prelude::*;
97
use std::path::Path;
108

119
pub fn check(path: &Path, bad: &mut bool) {
12-
let mut contents = String::new();
1310
let mut map: HashMap<_, Vec<_>> = HashMap::new();
1411
super::walk(path,
1512
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
16-
&mut |file| {
13+
&mut |entry, contents| {
14+
let file = entry.path();
1715
let filename = file.file_name().unwrap().to_string_lossy();
1816
if filename != "error_codes.rs" {
1917
return
2018
}
2119

22-
contents.truncate(0);
23-
t!(t!(File::open(file)).read_to_string(&mut contents));
24-
2520
// In the `register_long_diagnostics!` macro, entries look like this:
2621
//
2722
// ```

‎src/tools/tidy/src/features.rs

Lines changed: 75 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
1212
use std::collections::HashMap;
1313
use std::fmt;
14-
use std::fs::{self, File};
15-
use std::io::prelude::*;
14+
use std::fs;
1615
use std::path::Path;
1716

18-
use regex::{Regex, escape};
17+
use regex::Regex;
1918

2019
mod version;
2120
use version::Version;
@@ -51,20 +50,48 @@ pub struct Feature {
5150

5251
pub type Features = HashMap<String, Feature>;
5352

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 {
5583
let mut features = collect_lang_features(path, bad);
5684
assert!(!features.is_empty());
5785

5886
let lib_features = get_and_check_lib_features(path, bad, &features);
5987
assert!(!lib_features.is_empty());
6088

61-
let mut contents = String::new();
62-
6389
super::walk_many(&[&path.join("test/ui"),
6490
&path.join("test/ui-fulldeps"),
6591
&path.join("test/compile-fail")],
6692
&mut |path| super::filter_dirs(path),
67-
&mut |file| {
93+
&mut |entry, contents| {
94+
let file = entry.path();
6895
let filename = file.file_name().unwrap().to_string_lossy();
6996
if !filename.ends_with(".rs") || filename == "features.rs" ||
7097
filename == "diagnostic_list.rs" {
@@ -74,9 +101,6 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
74101
let filen_underscore = filename.replace('-',"_").replace(".rs","");
75102
let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);
76103

77-
contents.truncate(0);
78-
t!(t!(File::open(&file), &file).read_to_string(&mut contents));
79-
80104
for (i, line) in contents.lines().enumerate() {
81105
let mut err = |msg: &str| {
82106
tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
@@ -130,21 +154,23 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
130154
}
131155

132156
if *bad {
133-
return;
134-
}
135-
if quiet {
136-
println!("* {} features", features.len());
137-
return;
157+
return CollectedFeatures { lib: lib_features, lang: features };
138158
}
139159

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"));
143164

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());
147171
}
172+
173+
CollectedFeatures { lib: lib_features, lang: features }
148174
}
149175

150176
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
159185
}
160186

161187
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+
164201
r.captures(line)
165202
.and_then(|c| c.get(1))
166203
.map(|m| m.as_str())
@@ -175,9 +212,11 @@ fn test_find_attr_val() {
175212
}
176213

177214
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) {
179217
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 {
181220
f.has_gate_test = true;
182221
return true;
183222
}
@@ -295,32 +334,6 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
295334
.collect()
296335
}
297336

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-
324337
fn get_and_check_lib_features(base_src_path: &Path,
325338
bad: &mut bool,
326339
lang_features: &Features) -> Features {
@@ -355,20 +368,25 @@ fn get_and_check_lib_features(base_src_path: &Path,
355368

356369
fn map_lib_features(base_src_path: &Path,
357370
mf: &mut dyn FnMut(Result<(&str, Feature), &str>, &Path, usize)) {
358-
let mut contents = String::new();
359371
super::walk(base_src_path,
360372
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
361-
&mut |file| {
373+
&mut |entry, contents| {
374+
let file = entry.path();
362375
let filename = file.file_name().unwrap().to_string_lossy();
363376
if !filename.ends_with(".rs") || filename == "features.rs" ||
364377
filename == "diagnostic_list.rs" {
365378
return;
366379
}
367380

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+
}
370388

371-
let mut becoming_feature: Option<(String, Feature)> = None;
389+
let mut becoming_feature: Option<(&str, Feature)> = None;
372390
for (i, line) in contents.lines().enumerate() {
373391
macro_rules! err {
374392
($msg:expr) => {{
@@ -447,7 +465,7 @@ fn map_lib_features(base_src_path: &Path,
447465
if line.contains(']') {
448466
mf(Ok((feature_name, feature)), file, i + 1);
449467
} else {
450-
becoming_feature = Some((feature_name.to_owned(), feature));
468+
becoming_feature = Some((feature_name, feature));
451469
}
452470
}
453471
});

‎src/tools/tidy/src/lib.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
//! This library contains the tidy lints and exposes it
44
//! to be used by tools.
55
6-
use std::fs;
6+
use walkdir::{DirEntry, WalkDir};
7+
use std::fs::File;
8+
use std::io::Read;
79

810
use std::path::Path;
911

@@ -65,25 +67,35 @@ fn filter_dirs(path: &Path) -> bool {
6567
skip.iter().any(|p| path.ends_with(p))
6668
}
6769

68-
fn walk_many(paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&Path)) {
70+
71+
fn walk_many(
72+
paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)
73+
) {
6974
for path in paths {
7075
walk(path, skip, f);
7176
}
7277
}
7378

74-
fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&Path)) {
75-
if let Ok(dir) = fs::read_dir(path) {
76-
for entry in dir {
77-
let entry = t!(entry);
78-
let kind = t!(entry.file_type());
79-
let path = entry.path();
80-
if kind.is_dir() {
81-
if !skip(&path) {
82-
walk(&path, skip, f);
83-
}
84-
} else {
85-
f(&path);
79+
fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
80+
let mut contents = String::new();
81+
walk_no_read(path, skip, &mut |entry| {
82+
contents.clear();
83+
if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
84+
contents.clear();
85+
}
86+
f(&entry, &contents);
87+
});
88+
}
89+
90+
fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) {
91+
let walker = WalkDir::new(path).into_iter()
92+
.filter_entry(|e| !skip(e.path()));
93+
for entry in walker {
94+
if let Ok(entry) = entry {
95+
if entry.file_type().is_dir() {
96+
continue;
8697
}
98+
f(&entry);
8799
}
88100
}
89101
}

‎src/tools/tidy/src/libcoretest.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,22 @@
44
//! item. All tests must be written externally in `libcore/tests`.
55
66
use std::path::Path;
7-
use std::fs::read_to_string;
87

98
pub fn check(path: &Path, bad: &mut bool) {
109
let libcore_path = path.join("libcore");
1110
super::walk(
1211
&libcore_path,
1312
&mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
14-
&mut |subpath| {
13+
&mut |entry, contents| {
14+
let subpath = entry.path();
1515
if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
16-
match read_to_string(subpath) {
17-
Ok(contents) => {
18-
if contents.contains("#[test]") {
19-
tidy_error!(
20-
bad,
21-
"{} contains #[test]; libcore tests must be placed inside \
22-
`src/libcore/tests/`",
23-
subpath.display()
24-
);
25-
}
26-
}
27-
Err(err) => {
28-
panic!("failed to read file {:?}: {}", subpath, err);
29-
}
16+
if contents.contains("#[test]") {
17+
tidy_error!(
18+
bad,
19+
"{} contains #[test]; libcore tests must be placed inside \
20+
`src/libcore/tests/`",
21+
subpath.display()
22+
);
3023
}
3124
}
3225
},

‎src/tools/tidy/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ fn main() {
1919
let args: Vec<String> = env::args().skip(1).collect();
2020

2121
let mut bad = false;
22-
let quiet = args.iter().any(|s| *s == "--quiet");
22+
let verbose = args.iter().any(|s| *s == "--verbose");
2323
bins::check(&path, &mut bad);
2424
style::check(&path, &mut bad);
2525
errors::check(&path, &mut bad);
2626
cargo::check(&path, &mut bad);
27-
features::check(&path, &mut bad, quiet);
27+
let collected = features::check(&path, &mut bad, verbose);
2828
pal::check(&path, &mut bad);
29-
unstable_book::check(&path, &mut bad);
29+
unstable_book::check(&path, collected, &mut bad);
3030
libcoretest::check(&path, &mut bad);
3131
if !args.iter().any(|s| *s == "--no-vendor") {
3232
deps::check(&path, &mut bad);

‎src/tools/tidy/src/pal.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
//! platform-specific cfgs are allowed. Not sure yet how to deal with
3232
//! this in the long term.
3333
34-
use std::fs::File;
35-
use std::io::Read;
3634
use std::path::Path;
3735
use std::iter::Iterator;
3836

@@ -87,29 +85,26 @@ const EXCEPTION_PATHS: &[&str] = &[
8785
];
8886

8987
pub fn check(path: &Path, bad: &mut bool) {
90-
let mut contents = String::new();
9188
// Sanity check that the complex parsing here works.
9289
let mut saw_target_arch = false;
9390
let mut saw_cfg_bang = false;
94-
super::walk(path, &mut super::filter_dirs, &mut |file| {
91+
super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
92+
let file = entry.path();
9593
let filestr = file.to_string_lossy().replace("\\", "/");
9694
if !filestr.ends_with(".rs") { return }
9795

9896
let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
9997
if is_exception_path { return }
10098

101-
check_cfgs(&mut contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
99+
check_cfgs(contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
102100
});
103101

104102
assert!(saw_target_arch);
105103
assert!(saw_cfg_bang);
106104
}
107105

108-
fn check_cfgs(contents: &mut String, file: &Path,
106+
fn check_cfgs(contents: &str, file: &Path,
109107
bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
110-
contents.truncate(0);
111-
t!(t!(File::open(file), file).read_to_string(contents));
112-
113108
// For now it's ok to have platform-specific code after 'mod tests'.
114109
let mod_tests_idx = find_test_mod(contents);
115110
let contents = &contents[..mod_tests_idx];

‎src/tools/tidy/src/style.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
//! A number of these checks can be opted-out of with various directives of the form:
1414
//! `// ignore-tidy-CHECK-NAME`.
1515
16-
use std::fs::File;
17-
use std::io::prelude::*;
1816
use std::path::Path;
1917

2018
const COLS: usize = 100;
@@ -109,7 +107,11 @@ enum Directive {
109107
Ignore(bool),
110108
}
111109

112-
fn contains_ignore_directive(contents: &String, check: &str) -> Directive {
110+
fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive {
111+
if !can_contain {
112+
return Directive::Deny;
113+
}
114+
// Update `can_contain` when changing this
113115
if contents.contains(&format!("// ignore-tidy-{}", check)) ||
114116
contents.contains(&format!("# ignore-tidy-{}", check)) {
115117
Directive::Ignore(false)
@@ -129,28 +131,28 @@ macro_rules! suppressible_tidy_err {
129131
}
130132

131133
pub fn check(path: &Path, bad: &mut bool) {
132-
let mut contents = String::new();
133-
super::walk(path, &mut super::filter_dirs, &mut |file| {
134+
super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
135+
let file = entry.path();
134136
let filename = file.file_name().unwrap().to_string_lossy();
135137
let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"];
136138
if extensions.iter().all(|e| !filename.ends_with(e)) ||
137139
filename.starts_with(".#") {
138140
return
139141
}
140142

141-
contents.truncate(0);
142-
t!(t!(File::open(file), file).read_to_string(&mut contents));
143-
144143
if contents.is_empty() {
145144
tidy_error!(bad, "{}: empty file", file.display());
146145
}
147146

148-
let mut skip_cr = contains_ignore_directive(&contents, "cr");
149-
let mut skip_tab = contains_ignore_directive(&contents, "tab");
150-
let mut skip_line_length = contains_ignore_directive(&contents, "linelength");
151-
let mut skip_file_length = contains_ignore_directive(&contents, "filelength");
152-
let mut skip_end_whitespace = contains_ignore_directive(&contents, "end-whitespace");
153-
let mut skip_copyright = contains_ignore_directive(&contents, "copyright");
147+
let can_contain = contents.contains("// ignore-tidy-") ||
148+
contents.contains("# ignore-tidy-");
149+
let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
150+
let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
151+
let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
152+
let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
153+
let mut skip_end_whitespace =
154+
contains_ignore_directive(can_contain, &contents, "end-whitespace");
155+
let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
154156
let mut leading_new_lines = false;
155157
let mut trailing_new_lines = 0;
156158
let mut lines = 0;

‎src/tools/tidy/src/ui_tests.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ use std::fs;
44
use std::path::Path;
55

66
pub fn check(path: &Path, bad: &mut bool) {
7-
super::walk_many(
8-
&[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
9-
&mut |_| false,
10-
&mut |file_path| {
7+
for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] {
8+
super::walk_no_read(path, &mut |_| false, &mut |entry| {
9+
let file_path = entry.path();
1110
if let Some(ext) = file_path.extension() {
1211
if ext == "stderr" || ext == "stdout" {
1312
// Test output filenames have one of the formats:
@@ -45,6 +44,6 @@ pub fn check(path: &Path, bad: &mut bool) {
4544
}
4645
}
4746
}
48-
},
49-
);
47+
});
48+
}
5049
}

‎src/tools/tidy/src/unstable_book.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::BTreeSet;
22
use std::fs;
3-
use std::path;
4-
use crate::features::{collect_lang_features, collect_lib_features, Features, Status};
3+
use std::path::{PathBuf, Path};
4+
use crate::features::{CollectedFeatures, Features, Feature, Status};
55

66
pub const PATH_STR: &str = "doc/unstable-book";
77

@@ -12,19 +12,19 @@ pub const LANG_FEATURES_DIR: &str = "src/language-features";
1212
pub const LIB_FEATURES_DIR: &str = "src/library-features";
1313

1414
/// Builds the path to the Unstable Book source directory from the Rust 'src' directory.
15-
pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf {
15+
pub fn unstable_book_path(base_src_path: &Path) -> PathBuf {
1616
base_src_path.join(PATH_STR)
1717
}
1818

1919
/// Builds the path to the directory where the features are documented within the Unstable Book
2020
/// source directory.
21-
pub fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf {
21+
pub fn unstable_book_lang_features_path(base_src_path: &Path) -> PathBuf {
2222
unstable_book_path(base_src_path).join(LANG_FEATURES_DIR)
2323
}
2424

2525
/// Builds the path to the directory where the features are documented within the Unstable Book
2626
/// source directory.
27-
pub fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf {
27+
pub fn unstable_book_lib_features_path(base_src_path: &Path) -> PathBuf {
2828
unstable_book_path(base_src_path).join(LIB_FEATURES_DIR)
2929
}
3030

@@ -45,7 +45,7 @@ pub fn collect_unstable_feature_names(features: &Features) -> BTreeSet<String> {
4545
.collect()
4646
}
4747

48-
pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet<String> {
48+
pub fn collect_unstable_book_section_file_names(dir: &Path) -> BTreeSet<String> {
4949
fs::read_dir(dir)
5050
.expect("could not read directory")
5151
.map(|entry| entry.expect("could not read directory entry"))
@@ -60,7 +60,7 @@ pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet<St
6060
///
6161
/// * hyphens replaced by underscores,
6262
/// * the markdown suffix ('.md') removed.
63-
fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::Path)
63+
fn collect_unstable_book_lang_features_section_file_names(base_src_path: &Path)
6464
-> BTreeSet<String> {
6565
collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path))
6666
}
@@ -69,18 +69,26 @@ fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::
6969
///
7070
/// * hyphens replaced by underscores,
7171
/// * the markdown suffix ('.md') removed.
72-
fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path)
73-
-> BTreeSet<String> {
72+
fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) -> BTreeSet<String> {
7473
collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path))
7574
}
7675

77-
pub fn check(path: &path::Path, bad: &mut bool) {
78-
// Library features
79-
80-
let lang_features = collect_lang_features(path, bad);
81-
let lib_features = collect_lib_features(path).into_iter().filter(|&(ref name, _)| {
76+
pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) {
77+
let lang_features = features.lang;
78+
let mut lib_features = features.lib.into_iter().filter(|&(ref name, _)| {
8279
!lang_features.contains_key(name)
83-
}).collect();
80+
}).collect::<Features>();
81+
82+
// This library feature is defined in the `compiler_builtins` crate, which
83+
// has been moved out-of-tree. Now it can no longer be auto-discovered by
84+
// `tidy`, because we need to filter out its (submodule) directory. Manually
85+
// add it to the set of known library features so we can still generate docs.
86+
lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
87+
level: Status::Unstable,
88+
since: None,
89+
has_gate_test: false,
90+
tracking_issue: None,
91+
});
8492

8593
// Library features
8694
let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features);

0 commit comments

Comments
 (0)
Please sign in to comment.