Skip to content

Commit 4691e61

Browse files
authored
Rollup merge of #154352 - notriddle:emit-md, r=fmease
rustdoc: dep-info for standalone markdown inputs Part of #146220 (comment) r? @fmease
2 parents 7e40efc + bfaf027 commit 4691e61

7 files changed

Lines changed: 97 additions & 16 deletions

File tree

src/librustdoc/config.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -756,10 +756,12 @@ impl Options {
756756
}
757757

758758
let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
759-
if let Some(ref index_page) = index_page
760-
&& !index_page.is_file()
761-
{
762-
dcx.fatal("option `--index-page` argument must be a file");
759+
if let Some(ref index_page) = index_page {
760+
if index_page.is_file() {
761+
loaded_paths.push(index_page.clone());
762+
} else {
763+
dcx.fatal("option `--index-page` argument must be a file");
764+
}
763765
}
764766

765767
let target = parse_target_triple(early_dcx, matches);

src/librustdoc/html/render/write_shared.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ pub(crate) fn write_shared(
118118
let mut md_opts = opt.clone();
119119
md_opts.output = cx.dst.clone();
120120
md_opts.external_html = cx.shared.layout.external_html.clone();
121+
let file = try_err!(cx.sess().source_map().load_file(&index_page), &index_page);
121122
try_err!(
122-
crate::markdown::render_and_write(index_page, md_opts, cx.shared.edition()),
123+
crate::markdown::render_and_write(file, md_opts, cx.shared.edition()),
123124
&index_page
124125
);
125126
}

src/librustdoc/lib.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,14 @@ use std::io::{self, IsTerminal};
7070
use std::path::Path;
7171
use std::process::ExitCode;
7272

73+
use rustc_ast::ast;
7374
use rustc_errors::DiagCtxtHandle;
7475
use rustc_hir::def_id::LOCAL_CRATE;
7576
use rustc_interface::interface;
7677
use rustc_middle::ty::TyCtxt;
7778
use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
7879
use rustc_session::{EarlyDiagCtxt, getopts};
80+
use rustc_span::{BytePos, Span, SyntaxContext};
7981
use tracing::info;
8082

8183
use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION;
@@ -836,8 +838,39 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
836838
// `run_compiler`.
837839
return wrap_return(
838840
dcx,
839-
interface::run_compiler(config, |_compiler| {
840-
markdown::render_and_write(&md_input, render_options, edition)
841+
interface::run_compiler(config, |compiler| {
842+
// construct a phony "crate" without actually running the parser
843+
// allows us to use other compiler infrastructure like dep-info
844+
let file =
845+
compiler.sess.source_map().load_file(&md_input).map_err(|e| {
846+
format!("{md_input}: {e}", md_input = md_input.display())
847+
})?;
848+
let inner_span = Span::new(
849+
file.start_pos,
850+
BytePos(file.start_pos.0 + file.normalized_source_len.0),
851+
SyntaxContext::root(),
852+
None,
853+
);
854+
let krate = ast::Crate {
855+
attrs: Default::default(),
856+
items: Default::default(),
857+
spans: ast::ModSpans { inner_span, ..Default::default() },
858+
id: ast::DUMMY_NODE_ID,
859+
is_placeholder: false,
860+
};
861+
rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
862+
let has_dep_info = render_options.dep_info().is_some();
863+
markdown::render_and_write(file, render_options, edition)?;
864+
if has_dep_info {
865+
// Register the loaded external files in the source map so they show up in depinfo.
866+
// We can't load them via the source map because it gets created after we process the options.
867+
for external_path in &loaded_paths {
868+
let _ = compiler.sess.source_map().load_binary_file(external_path);
869+
}
870+
rustc_interface::passes::write_dep_info(tcx);
871+
}
872+
Ok(())
873+
})
841874
}),
842875
);
843876
}

src/librustdoc/markdown.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files
1010
1111
use std::fmt::{self, Write as _};
12-
use std::fs::{File, create_dir_all, read_to_string};
12+
use std::fs::{File, create_dir_all};
1313
use std::io::prelude::*;
14-
use std::path::Path;
14+
use std::path::PathBuf;
15+
use std::sync::Arc;
1516

17+
use rustc_span::SourceFile;
1618
use rustc_span::edition::Edition;
1719

1820
use crate::config::RenderOptions;
@@ -43,18 +45,18 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
4345
/// (e.g., output = "bar" => "bar/foo.html").
4446
///
4547
/// Requires session globals to be available, for symbol interning.
46-
pub(crate) fn render_and_write<P: AsRef<Path>>(
47-
input: P,
48+
pub(crate) fn render_and_write(
49+
input: Arc<SourceFile>,
4850
options: RenderOptions,
4951
edition: Edition,
5052
) -> Result<(), String> {
5153
if let Err(e) = create_dir_all(&options.output) {
5254
return Err(format!("{output}: {e}", output = options.output.display()));
5355
}
5456

55-
let input = input.as_ref();
57+
let input_path = input.name.clone().into_local_path().unwrap_or(PathBuf::new());
5658
let mut output = options.output;
57-
output.push(input.file_name().unwrap());
59+
output.push(input_path.file_name().unwrap());
5860
output.set_extension("html");
5961

6062
let mut css = String::new();
@@ -63,8 +65,7 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
6365
.expect("Writing to a String can't fail");
6466
}
6567

66-
let input_str =
67-
read_to_string(input).map_err(|err| format!("{input}: {err}", input = input.display()))?;
68+
let input_str = input.src.as_ref().map(|src| &src[..]).unwrap_or("");
6869
let playground_url = options.markdown_playground_url.or(options.playground_url);
6970
let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url });
7071

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
% My Example
2+
3+
First and only paragraph.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
% Index page
2+
3+
Index page

tests/run-make/rustdoc-dep-info/rmake.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
//@ needs-target-std
55

6-
use run_make_support::assertion_helpers::assert_contains;
6+
use run_make_support::assertion_helpers::{assert_contains, assert_not_contains};
77
use run_make_support::{path, rfs, rustdoc};
88

99
fn main() {
@@ -19,6 +19,7 @@ fn main() {
1919
.arg("--markdown-after-content=after.md")
2020
.arg("--extend-css=extend.css")
2121
.arg("--theme=theme.css")
22+
.arg("--index-page=index-page.md")
2223
.emit("dep-info")
2324
.run();
2425

@@ -31,6 +32,7 @@ fn main() {
3132
assert_contains(&content, "before.html:");
3233
assert_contains(&content, "extend.css:");
3334
assert_contains(&content, "theme.css:");
35+
assert_contains(&content, "index-page.md:");
3436

3537
// Now we check that we can provide a file name to the `dep-info` argument.
3638
rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run();
@@ -58,4 +60,40 @@ fn main() {
5860
assert!(!path("precedence1.d").exists());
5961
assert!(!path("-").exists()); // `-` shouldn't be treated as a file path
6062
assert!(!result.stdout().is_empty()); // Something emitted to stdout
63+
64+
// test --emit=dep-info combined with plain markdown input
65+
rustdoc().input("example.md").arg("-Zunstable-options").emit("dep-info").run();
66+
let content = rfs::read_to_string("doc/example.d");
67+
assert_contains(&content, "example.md:");
68+
assert_not_contains(&content, "lib.rs:");
69+
assert_not_contains(&content, "foo.rs:");
70+
assert_not_contains(&content, "bar.rs:");
71+
assert_not_contains(&content, "doc.md:");
72+
assert_not_contains(&content, "after.md:");
73+
assert_not_contains(&content, "before.html:");
74+
assert_not_contains(&content, "extend.css:");
75+
assert_not_contains(&content, "theme.css:");
76+
77+
// combine --emit=dep-info=filename with plain markdown input
78+
rustdoc()
79+
.input("example.md")
80+
.arg("-Zunstable-options")
81+
.arg("--html-before-content=before.html")
82+
.arg("--markdown-after-content=after.md")
83+
.arg("--extend-css=extend.css")
84+
.arg("--theme=theme.css")
85+
.arg("--index-page=index-page.md")
86+
.emit("dep-info=example.d")
87+
.run();
88+
let content = rfs::read_to_string("example.d");
89+
assert_contains(&content, "example.md:");
90+
assert_not_contains(&content, "lib.rs:");
91+
assert_not_contains(&content, "foo.rs:");
92+
assert_not_contains(&content, "bar.rs:");
93+
assert_not_contains(&content, "doc.md:");
94+
assert_contains(&content, "after.md:");
95+
assert_contains(&content, "before.html:");
96+
assert_contains(&content, "extend.css:");
97+
assert_contains(&content, "theme.css:");
98+
assert_contains(&content, "index-page.md:");
6199
}

0 commit comments

Comments
 (0)