Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Move some arguments to fields and reorganize fields
I moved some local arguments and options to either the local options
struct or, if it made sense, the global options struct.
  • Loading branch information
camelid authored and GuillaumeGomez committed Jun 7, 2024
commit 366000dc07340abfeba6de1d9e7db0913304fa59
74 changes: 30 additions & 44 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,19 @@ use crate::lint::init_lints;
use self::rust::HirCollector;

/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
#[derive(Clone, Default)]
#[derive(Clone)]
pub(crate) struct GlobalTestOptions {
/// Name of the crate (for regular `rustdoc`) or Markdown file (for `rustdoc foo.md`).
pub(crate) crate_name: String,
/// Whether to disable the default `extern crate my_crate;` when creating doctests.
pub(crate) no_crate_inject: bool,
/// Whether inserting extra indent spaces in code block,
/// default is `false`, only `true` for generating code link of Rust playground
pub(crate) insert_indent_space: bool,
/// Additional crate-level attributes to add to doctests.
pub(crate) attrs: Vec<String>,
/// Path to file containing arguments for the invocation of rustc.
pub(crate) args_file: PathBuf,
}

pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> {
Expand Down Expand Up @@ -167,24 +171,19 @@ pub(crate) fn run(
Ok(temp_dir) => temp_dir,
Err(error) => return crate::wrap_return(dcx, Err(error)),
};
let file_path = temp_dir.path().join("rustdoc-cfgs");
crate::wrap_return(dcx, generate_args_file(&file_path, &options))?;
let args_path = temp_dir.path().join("rustdoc-cfgs");
crate::wrap_return(dcx, generate_args_file(&args_path, &options))?;

let (tests, unused_extern_reports, compiling_test_count) =
interface::run_compiler(config, |compiler| {
compiler.enter(|queries| {
let collector = queries.global_ctxt()?.enter(|tcx| {
let crate_name = tcx.crate_name(LOCAL_CRATE).to_string();
let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);

let opts = scrape_test_config(crate_attrs);
let opts = scrape_test_config(crate_name, crate_attrs, args_path);
let enable_per_target_ignores = options.enable_per_target_ignores;
let mut collector = CreateRunnableDoctests::new(
tcx.crate_name(LOCAL_CRATE).to_string(),
options,
opts,
file_path,
);

let mut collector = CreateRunnableDoctests::new(options, opts);
let hir_collector = HirCollector::new(
&compiler.sess,
tcx.hir(),
Expand Down Expand Up @@ -264,11 +263,20 @@ pub(crate) fn run_tests(
}

// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions {
fn scrape_test_config(
crate_name: String,
attrs: &[ast::Attribute],
args_file: PathBuf,
) -> GlobalTestOptions {
use rustc_ast_pretty::pprust;

let mut opts =
GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false };
let mut opts = GlobalTestOptions {
crate_name,
no_crate_inject: false,
attrs: Vec::new(),
insert_indent_space: false,
args_file,
};

let test_attrs: Vec<_> = attrs
.iter()
Expand Down Expand Up @@ -363,20 +371,18 @@ fn wrapped_rustc_command(rustc_wrappers: &[PathBuf], rustc_binary: &Path) -> Com

fn run_test(
test: &str,
crate_name: &str,
line: usize,
rustdoc_options: &RustdocOptions,
test_options: IndividualTestOptions,
mut lang_string: LangString,
no_run: bool,
opts: &GlobalTestOptions,
edition: Edition,
path: PathBuf,
report_unused_externs: impl Fn(UnusedExterns),
) -> Result<(), TestFailure> {
let (test, line_offset, supports_color) = make_test(
test,
Some(crate_name),
Some(&opts.crate_name),
lang_string.test_harness,
opts,
edition,
Expand All @@ -393,14 +399,14 @@ fn run_test(
.unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);

compiler.arg(&format!("@{}", test_options.arg_file.display()));
compiler.arg(&format!("@{}", opts.args_file.display()));

if let Some(sysroot) = &rustdoc_options.maybe_sysroot {
compiler.arg(format!("--sysroot={}", sysroot.display()));
}

compiler.arg("--edition").arg(&edition.to_string());
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path);
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &test_options.path);
compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", format!("{}", line as isize - line_offset as isize));
compiler.arg("-o").arg(&output_file);
if lang_string.test_harness {
Expand Down Expand Up @@ -926,13 +932,13 @@ fn partition_source(s: &str, edition: Edition) -> (String, String, String) {
}

pub(crate) struct IndividualTestOptions {
arg_file: PathBuf,
outdir: DirState,
test_id: String,
path: PathBuf,
}

impl IndividualTestOptions {
fn new(options: &RustdocOptions, arg_file: &Path, test_id: String) -> Self {
fn new(options: &RustdocOptions, test_id: String, test_path: PathBuf) -> Self {
let outdir = if let Some(ref path) = options.persist_doctests {
let mut path = path.clone();
path.push(&test_id);
Expand All @@ -947,7 +953,7 @@ impl IndividualTestOptions {
DirState::Temp(get_doctest_dir().expect("rustdoc needs a tempdir"))
};

Self { arg_file: arg_file.into(), outdir, test_id }
Self { outdir, test_id, path: test_path }
}
}

Expand Down Expand Up @@ -979,30 +985,24 @@ pub(crate) struct CreateRunnableDoctests {
pub(crate) tests: Vec<test::TestDescAndFn>,

rustdoc_options: Arc<RustdocOptions>,
crate_name: String,
opts: GlobalTestOptions,
visited_tests: FxHashMap<(String, usize), usize>,
unused_extern_reports: Arc<Mutex<Vec<UnusedExterns>>>,
compiling_test_count: AtomicUsize,
arg_file: PathBuf,
}

impl CreateRunnableDoctests {
pub(crate) fn new(
crate_name: String,
rustdoc_options: RustdocOptions,
opts: GlobalTestOptions,
arg_file: PathBuf,
) -> CreateRunnableDoctests {
CreateRunnableDoctests {
tests: Vec::new(),
rustdoc_options: Arc::new(rustdoc_options),
crate_name,
opts,
visited_tests: FxHashMap::default(),
unused_extern_reports: Default::default(),
compiling_test_count: AtomicUsize::new(0),
arg_file,
}
}

Expand All @@ -1017,7 +1017,6 @@ impl CreateRunnableDoctests {

fn add_test(&mut self, test: ScrapedDoctest) {
let name = self.generate_name(&test.filename, test.line, &test.logical_path);
let crate_name = self.crate_name.clone();
let opts = self.opts.clone();
let target_str = self.rustdoc_options.target.to_string();
let unused_externs = self.unused_extern_reports.clone();
Expand Down Expand Up @@ -1060,8 +1059,7 @@ impl CreateRunnableDoctests {
);

let rustdoc_options = self.rustdoc_options.clone();
let rustdoc_test_options =
IndividualTestOptions::new(&self.rustdoc_options, &self.arg_file, test_id);
let rustdoc_test_options = IndividualTestOptions::new(&self.rustdoc_options, test_id, path);

debug!("creating test {name}: {}", test.text);
self.tests.push(test::TestDescAndFn {
Expand All @@ -1085,25 +1083,15 @@ impl CreateRunnableDoctests {
test_type: test::TestType::DocTest,
},
testfn: test::DynTestFn(Box::new(move || {
doctest_run_fn(
crate_name,
rustdoc_test_options,
opts,
path,
test,
rustdoc_options,
unused_externs,
)
doctest_run_fn(rustdoc_test_options, opts, test, rustdoc_options, unused_externs)
})),
});
}
}

fn doctest_run_fn(
crate_name: String,
test_opts: IndividualTestOptions,
global_opts: GlobalTestOptions,
path: PathBuf,
scraped_test: ScrapedDoctest,
rustdoc_options: Arc<RustdocOptions>,
unused_externs: Arc<Mutex<Vec<UnusedExterns>>>,
Expand All @@ -1115,15 +1103,13 @@ fn doctest_run_fn(
let edition = scraped_test.edition(&rustdoc_options);
let res = run_test(
&scraped_test.text,
&crate_name,
scraped_test.line,
&rustdoc_options,
test_opts,
scraped_test.langstr,
no_run,
&global_opts,
edition,
path,
report_unused_externs,
);

Expand Down
26 changes: 14 additions & 12 deletions src/librustdoc/doctest/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl DoctestVisitor for MdCollector {
}
}

/// Runs any tests/code examples in the markdown file `input`.
/// Runs any tests/code examples in the markdown file `options.input`.
pub(crate) fn test(options: Options) -> Result<(), String> {
use rustc_session::config::Input;
let input_str = match &options.input {
Expand All @@ -83,13 +83,20 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
Input::Str { name: _, input } => input.clone(),
};

let mut opts = GlobalTestOptions::default();
opts.no_crate_inject = true;

// Obviously not a real crate name, but close enough for purposes of doctests.
let crate_name = options.input.filestem().to_string();
let temp_dir =
tempdir().map_err(|error| format!("failed to create temporary directory: {error:?}"))?;
let file_path = temp_dir.path().join("rustdoc-cfgs");
generate_args_file(&file_path, &options)?;
let args_file = temp_dir.path().join("rustdoc-cfgs");
generate_args_file(&args_file, &options)?;

let opts = GlobalTestOptions {
crate_name,
no_crate_inject: true,
insert_indent_space: false,
attrs: vec![],
args_file,
};

let mut md_collector = MdCollector {
tests: vec![],
Expand All @@ -111,12 +118,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
None,
);

let mut collector = CreateRunnableDoctests::new(
options.input.filestem().to_string(),
options.clone(),
opts,
file_path,
);
let mut collector = CreateRunnableDoctests::new(options.clone(), opts);
md_collector.tests.into_iter().for_each(|t| collector.add_test(t));
crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
Ok(())
Expand Down
12 changes: 10 additions & 2 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use std::collections::VecDeque;
use std::fmt::Write;
use std::iter::Peekable;
use std::ops::{ControlFlow, Range};
use std::path::PathBuf;
use std::str::{self, CharIndices};
use std::sync::OnceLock;

Expand Down Expand Up @@ -287,8 +288,15 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
.collect::<String>();
let krate = krate.as_ref().map(|s| s.as_str());

let mut opts: GlobalTestOptions = Default::default();
opts.insert_indent_space = true;
// FIXME: separate out the code to make a code block into runnable code
// from the complicated doctest logic
let opts = GlobalTestOptions {
crate_name: krate.map(String::from).unwrap_or_default(),
no_crate_inject: false,
insert_indent_space: true,
attrs: vec![],
args_file: PathBuf::new(),
};
let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None);
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };

Expand Down