Skip to content

Commit

Permalink
rustdoc: add - (stdin) support
Browse files Browse the repository at this point in the history
  • Loading branch information
Urgau committed May 1, 2024
1 parent 5d2914a commit 9f75f54
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 18 deletions.
9 changes: 5 additions & 4 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl TryFrom<&str> for OutputFormat {
pub(crate) struct Options {
// Basic options / Options passed directly to rustc
/// The crate root or Markdown file to load.
pub(crate) input: PathBuf,
pub(crate) input: String,
/// The name of the crate being documented.
pub(crate) crate_name: Option<String>,
/// Whether or not this is a bin crate
Expand Down Expand Up @@ -450,15 +450,16 @@ impl Options {

let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);

let input = PathBuf::from(if describe_lints {
let input = if describe_lints {
"" // dummy, this won't be used
} else if matches.free.is_empty() {
dcx.fatal("missing file operand");
} else if matches.free.len() > 1 {
dcx.fatal("too many file operands");
} else {
&matches.free[0]
});
}
.to_string();

let externs = parse_externs(early_dcx, matches, &unstable_opts);
let extern_html_root_urls = match parse_extern_html_roots(matches) {
Expand Down Expand Up @@ -797,7 +798,7 @@ impl Options {

/// Returns `true` if the file given as `self.input` is a Markdown file.
pub(crate) fn markdown_input(&self) -> bool {
self.input.extension().is_some_and(|e| e == "md" || e == "markdown")
self.input.rsplit_once('.').is_some_and(|(_, e)| e == "md" || e == "markdown")
}
}

Expand Down
30 changes: 26 additions & 4 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
use rustc_session::lint;
use rustc_session::EarlyDiagCtxt;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::{source_map, Span};
use rustc_span::{source_map, FileName, Span};

use std::cell::RefCell;
use std::io;
use std::io::Read;
use std::mem;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::LazyLock;
use std::sync::{atomic::AtomicBool, Arc};
Expand Down Expand Up @@ -174,10 +177,30 @@ pub(crate) fn new_dcx(
rustc_errors::DiagCtxt::new(emitter).with_flags(unstable_opts.dcx_flags(true))
}

/// Create the input (string or file path)
pub(crate) fn make_input(
early_dcx: &EarlyDiagCtxt,
input: &String,
) -> Result<Input, ErrorGuaranteed> {
Ok(if input == "-" {
let mut src = String::new();
if io::stdin().read_to_string(&mut src).is_err() {
// Immediately stop compilation if there was an issue reading
// the input (for example if the input stream is not UTF-8).
let reported =
early_dcx.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
return Err(reported);
}
Input::Str { name: FileName::anon_source_code(&src), input: src }
} else {
Input::File(PathBuf::from(input))
})
}

/// Parse, resolve, and typecheck the given crate.
pub(crate) fn create_config(
RustdocOptions {
input,
input: _,
crate_name,
proc_macro_crate,
error_format,
Expand All @@ -199,13 +222,12 @@ pub(crate) fn create_config(
..
}: RustdocOptions,
RenderOptions { document_private, .. }: &RenderOptions,
input: Input,
using_internal_features: Arc<AtomicBool>,
) -> rustc_interface::Config {
// Add the doc cfg into the doc build.
cfgs.push("doc".to_string());

let input = Input::File(input);

// By default, rustdoc ignores all lints.
// Specifically unblock lints relevant to documentation or the lint machinery itself.
let mut lints_to_show = vec![
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_parse::parser::attr::InnerAttrPolicy;
use rustc_resolve::rustdoc::span_of_fragments;
use rustc_session::config::Input;
use rustc_session::config::{self, CrateType, ErrorOutputType};
use rustc_session::parse::ParseSess;
use rustc_session::{lint, Session};
Expand Down Expand Up @@ -92,9 +93,8 @@ fn get_doctest_dir() -> io::Result<TempDir> {
pub(crate) fn run(
dcx: &rustc_errors::DiagCtxt,
options: RustdocOptions,
input: Input,
) -> Result<(), ErrorGuaranteed> {
let input = config::Input::File(options.input.clone());

let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;

// See core::create_config for what's going on here.
Expand Down
16 changes: 12 additions & 4 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,13 +729,21 @@ fn main_args(
let diag =
core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);

let input = core::make_input(early_dcx, &options.input)?;

match (options.should_test, options.markdown_input()) {
(true, true) => return wrap_return(&diag, markdown::test(options)),
(true, false) => return doctest::run(&diag, options),
(true, false) => return doctest::run(&diag, options, input),
(false, true) => {
let input = options.input.clone();
let edition = options.edition;
let config = core::create_config(options, &render_options, using_internal_features);
let config =
core::create_config(options, &render_options, input, using_internal_features);

use rustc_session::config::Input;
let input = match &config.input {
Input::File(path) => path.clone(),
Input::Str { .. } => unreachable!("only path to markdown are supported"),
};

// `markdown::render` can invoke `doctest::make_test`, which
// requires session globals and a thread pool, so we use
Expand Down Expand Up @@ -768,7 +776,7 @@ fn main_args(
let scrape_examples_options = options.scrape_examples_options.clone();
let bin_crate = options.bin_crate;

let config = core::create_config(options, &render_options, using_internal_features);
let config = core::create_config(options, &render_options, input, using_internal_features);

interface::run_compiler(config, |compiler| {
let sess = &compiler.sess;
Expand Down
8 changes: 4 additions & 4 deletions src/librustdoc/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Write as _;
use std::fs::{create_dir_all, read_to_string, File};
use std::io::prelude::*;
use std::path::Path;
use std::path::{Path, PathBuf};

use tempfile::tempdir;

Expand Down Expand Up @@ -145,7 +145,7 @@ pub(crate) fn render<P: AsRef<Path>>(
/// Runs any tests/code examples in the markdown file `input`.
pub(crate) fn test(options: Options) -> Result<(), String> {
let input_str = read_to_string(&options.input)
.map_err(|err| format!("{input}: {err}", input = options.input.display()))?;
.map_err(|err| format!("{input}: {err}", input = options.input))?;
let mut opts = GlobalTestOptions::default();
opts.no_crate_inject = true;

Expand All @@ -155,12 +155,12 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
generate_args_file(&file_path, &options)?;

let mut collector = Collector::new(
options.input.display().to_string(),
options.input.clone(),
options.clone(),
true,
opts,
None,
Some(options.input),
Some(PathBuf::from(options.input)),
options.enable_per_target_ignores,
file_path,
);
Expand Down
27 changes: 27 additions & 0 deletions tests/run-make/stdin-rustdoc/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! This test checks rustdoc `-` (stdin) handling

extern crate run_make_support;

use run_make_support::{rustdoc, tmp_dir};

const INPUT: &str = r#"
//! ```
//! dbg!(());
//! ```
pub struct F;
"#;

fn main() {
let tmp_dir = tmp_dir();
let out_dir = tmp_dir.join("doc");

// rustdoc -
rustdoc().arg("-").out_dir(&out_dir).run_with_stdin(INPUT);
assert!(out_dir.join("rust_out/struct.F.html").try_exists().unwrap());

// rustdoc --test -
rustdoc().arg("--test").arg("-").run_with_stdin(INPUT);

// rustdoc file.rs -
rustdoc().arg("file.rs").arg("-").run_fail();
}

0 comments on commit 9f75f54

Please sign in to comment.