Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 39f029a

Browse files
Split doctests between standalone and mergeable ones
1 parent 7d72482 commit 39f029a

File tree

5 files changed

+61
-29
lines changed

5 files changed

+61
-29
lines changed

src/librustdoc/doctest.rs

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, options: RustdocOptions) -> Result<()
164164
let args_path = temp_dir.path().join("rustdoc-cfgs");
165165
crate::wrap_return(dcx, generate_args_file(&args_path, &options))?;
166166

167-
let (tests, unused_extern_reports, compiling_test_count) =
167+
// FIXME: use mergeable tests!
168+
let (standalone_tests, unused_extern_reports, compiling_test_count) =
168169
interface::run_compiler(config, |compiler| {
169170
compiler.enter(|queries| {
170171
let collector = queries.global_ctxt()?.enter(|tcx| {
@@ -192,11 +193,11 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, options: RustdocOptions) -> Result<()
192193

193194
let unused_extern_reports = collector.unused_extern_reports.clone();
194195
let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
195-
Ok((collector.tests, unused_extern_reports, compiling_test_count))
196+
Ok((collector.standalone_tests, unused_extern_reports, compiling_test_count))
196197
})
197198
})?;
198199

199-
run_tests(test_args, nocapture, tests);
200+
run_tests(test_args, nocapture, standalone_tests);
200201

201202
// Collect and warn about unused externs, but only if we've gotten
202203
// reports for each doctest
@@ -617,7 +618,8 @@ pub(crate) trait DoctestVisitor {
617618
}
618619

619620
struct CreateRunnableDoctests {
620-
tests: Vec<test::TestDescAndFn>,
621+
standalone_tests: Vec<test::TestDescAndFn>,
622+
mergeable_tests: FxHashMap<Edition, Vec<(DocTest, ScrapedDoctest)>>,
621623

622624
rustdoc_options: Arc<RustdocOptions>,
623625
opts: GlobalTestOptions,
@@ -629,7 +631,8 @@ struct CreateRunnableDoctests {
629631
impl CreateRunnableDoctests {
630632
fn new(rustdoc_options: RustdocOptions, opts: GlobalTestOptions) -> CreateRunnableDoctests {
631633
CreateRunnableDoctests {
632-
tests: Vec::new(),
634+
standalone_tests: Vec::new(),
635+
mergeable_tests: FxHashMap::default(),
633636
rustdoc_options: Arc::new(rustdoc_options),
634637
opts,
635638
visited_tests: FxHashMap::default(),
@@ -647,16 +650,40 @@ impl CreateRunnableDoctests {
647650
format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly())
648651
}
649652

650-
fn add_test(&mut self, test: ScrapedDoctest) {
651-
let name = self.generate_name(&test.filename, test.line, &test.logical_path);
653+
fn add_test(&mut self, scraped_test: ScrapedDoctest) {
654+
let edition = scraped_test.edition(&self.rustdoc_options);
655+
let doctest = DocTest::new(&scraped_test.text, Some(&self.opts.crate_name), edition);
656+
let is_standalone = scraped_test.langstr.compile_fail
657+
|| scraped_test.langstr.test_harness
658+
|| self.rustdoc_options.nocapture
659+
|| self.rustdoc_options.test_args.iter().any(|arg| arg == "--show-output")
660+
|| doctest.crate_attrs.contains("#![no_std]");
661+
if is_standalone {
662+
let test_desc = self.generate_test_desc_and_fn(doctest, scraped_test);
663+
self.standalone_tests.push(test_desc);
664+
} else {
665+
self.mergeable_tests.entry(edition).or_default().push((doctest, scraped_test));
666+
}
667+
}
668+
669+
fn generate_test_desc_and_fn(
670+
&mut self,
671+
test: DocTest,
672+
scraped_test: ScrapedDoctest,
673+
) -> test::TestDescAndFn {
674+
let name = self.generate_name(
675+
&scraped_test.filename,
676+
scraped_test.line,
677+
&scraped_test.logical_path,
678+
);
652679
let opts = self.opts.clone();
653680
let target_str = self.rustdoc_options.target.to_string();
654681
let unused_externs = self.unused_extern_reports.clone();
655-
if !test.langstr.compile_fail {
682+
if !scraped_test.langstr.compile_fail {
656683
self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
657684
}
658685

659-
let path = match &test.filename {
686+
let path = match &scraped_test.filename {
660687
FileName::Real(path) => {
661688
if let Some(local_path) = path.local_path() {
662689
local_path.to_path_buf()
@@ -669,7 +696,7 @@ impl CreateRunnableDoctests {
669696
};
670697

671698
// For example `module/file.rs` would become `module_file_rs`
672-
let file = test
699+
let file = scraped_test
673700
.filename
674701
.prefer_local()
675702
.to_string_lossy()
@@ -679,12 +706,12 @@ impl CreateRunnableDoctests {
679706
let test_id = format!(
680707
"{file}_{line}_{number}",
681708
file = file,
682-
line = test.line,
709+
line = scraped_test.line,
683710
number = {
684711
// Increases the current test number, if this file already
685712
// exists or it creates a new entry with a test number of 0.
686713
self.visited_tests
687-
.entry((file.clone(), test.line))
714+
.entry((file.clone(), scraped_test.line))
688715
.and_modify(|v| *v += 1)
689716
.or_insert(0)
690717
},
@@ -693,11 +720,11 @@ impl CreateRunnableDoctests {
693720
let rustdoc_options = self.rustdoc_options.clone();
694721
let rustdoc_test_options = IndividualTestOptions::new(&self.rustdoc_options, test_id, path);
695722

696-
debug!("creating test {name}: {}", test.text);
697-
self.tests.push(test::TestDescAndFn {
723+
debug!("creating test {name}: {}", scraped_test.text);
724+
test::TestDescAndFn {
698725
desc: test::TestDesc {
699726
name: test::DynTestName(name),
700-
ignore: match test.langstr.ignore {
727+
ignore: match scraped_test.langstr.ignore {
701728
Ignore::All => true,
702729
Ignore::None => false,
703730
Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)),
@@ -710,30 +737,37 @@ impl CreateRunnableDoctests {
710737
end_col: 0,
711738
// compiler failures are test failures
712739
should_panic: test::ShouldPanic::No,
713-
compile_fail: test.langstr.compile_fail,
714-
no_run: test.no_run(&rustdoc_options),
740+
compile_fail: scraped_test.langstr.compile_fail,
741+
no_run: scraped_test.no_run(&rustdoc_options),
715742
test_type: test::TestType::DocTest,
716743
},
717744
testfn: test::DynTestFn(Box::new(move || {
718-
doctest_run_fn(rustdoc_test_options, opts, test, rustdoc_options, unused_externs)
745+
doctest_run_fn(
746+
rustdoc_test_options,
747+
opts,
748+
test,
749+
scraped_test,
750+
rustdoc_options,
751+
unused_externs,
752+
)
719753
})),
720-
});
754+
}
721755
}
722756
}
723757

724758
fn doctest_run_fn(
725759
test_opts: IndividualTestOptions,
726760
global_opts: GlobalTestOptions,
761+
doctest: DocTest,
727762
scraped_test: ScrapedDoctest,
728763
rustdoc_options: Arc<RustdocOptions>,
729764
unused_externs: Arc<Mutex<Vec<UnusedExterns>>>,
730765
) -> Result<(), String> {
731766
let report_unused_externs = |uext| {
732767
unused_externs.lock().unwrap().push(uext);
733768
};
734-
let edition = scraped_test.edition(&rustdoc_options);
735-
let doctest = DocTest::new(&scraped_test.text, Some(&global_opts.crate_name), edition);
736769
let (full_test_code, full_test_line_offset) = doctest.generate_unique_doctest(
770+
&scraped_test.text,
737771
scraped_test.langstr.test_harness,
738772
&global_opts,
739773
Some(&test_opts.test_id),

src/librustdoc/doctest/make.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_span::{FileName, Span, DUMMY_SP};
1818
use super::GlobalTestOptions;
1919

2020
pub(crate) struct DocTest {
21-
pub(crate) test_code: String,
2221
pub(crate) supports_color: bool,
2322
pub(crate) already_has_extern_crate: bool,
2423
pub(crate) main_fn_span: Option<Span>,
@@ -40,7 +39,6 @@ impl DocTest {
4039
// If the parser panicked due to a fatal error, pass the test code through unchanged.
4140
// The error will be reported during compilation.
4241
return DocTest {
43-
test_code: source.to_string(),
4442
supports_color: false,
4543
main_fn_span: None,
4644
crate_attrs,
@@ -50,7 +48,6 @@ impl DocTest {
5048
};
5149
};
5250
Self {
53-
test_code: source.to_string(),
5451
supports_color,
5552
main_fn_span,
5653
crate_attrs,
@@ -64,6 +61,7 @@ impl DocTest {
6461
/// lines before the test code begins.
6562
pub(crate) fn generate_unique_doctest(
6663
&self,
64+
test_code: &str,
6765
dont_insert_main: bool,
6866
opts: &GlobalTestOptions,
6967
// If `test_id` is `None`, it means we're generating code for a code example "run" link.
@@ -103,7 +101,7 @@ impl DocTest {
103101
// NOTE: this is terribly inaccurate because it doesn't actually
104102
// parse the source, but only has false positives, not false
105103
// negatives.
106-
self.test_code.contains(crate_name)
104+
test_code.contains(crate_name)
107105
{
108106
// rustdoc implicitly inserts an `extern crate` item for the own crate
109107
// which may be unused, so we need to allow the lint.

src/librustdoc/doctest/markdown.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,6 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
120120

121121
let mut collector = CreateRunnableDoctests::new(options.clone(), opts);
122122
md_collector.tests.into_iter().for_each(|t| collector.add_test(t));
123-
crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
123+
crate::doctest::run_tests(options.test_args, options.nocapture, collector.standalone_tests);
124124
Ok(())
125125
}

src/librustdoc/doctest/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn make_test(
1212
) -> (String, usize) {
1313
let doctest = DocTest::new(test_code, crate_name, DEFAULT_EDITION);
1414
let (code, line_offset) =
15-
doctest.generate_unique_doctest(dont_insert_main, opts, test_id, crate_name);
15+
doctest.generate_unique_doctest(test_code, dont_insert_main, opts, test_id, crate_name);
1616
(code, line_offset)
1717
}
1818

src/librustdoc/html/markdown.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,10 +298,10 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
298298
args_file: PathBuf::new(),
299299
};
300300
let doctest = doctest::DocTest::new(&test, krate, edition);
301-
let (test, _) = doctest.generate_unique_doctest(false, &opts, None, krate);
301+
let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, None, krate);
302302
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
303303

304-
let test_escaped = small_url_encode(doctest.test_code);
304+
let test_escaped = small_url_encode(test);
305305
Some(format!(
306306
"<a class=\"test-arrow\" \
307307
target=\"_blank\" \

0 commit comments

Comments
 (0)