set the default edition when pre-parsing a doctest

This commit is contained in:
QuietMisdreavus 2019-04-17 20:17:12 -05:00
parent a19cf18c7d
commit 20a5aa302e
8 changed files with 86 additions and 55 deletions

View File

@ -386,18 +386,6 @@ impl Options {
}
}
let mut id_map = html::markdown::IdMap::new();
id_map.populate(html::render::initial_ids());
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-in-header"),
&matches.opt_strs("html-before-content"),
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
Some(eh) => eh,
None => return Err(3),
};
let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
let edition = match edition.parse() {
Ok(e) => e,
@ -407,6 +395,19 @@ impl Options {
}
};
let mut id_map = html::markdown::IdMap::new();
id_map.populate(html::render::initial_ids());
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-in-header"),
&matches.opt_strs("html-before-content"),
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content"),
&diag, &mut id_map, edition) {
Some(eh) => eh,
None => return Err(3),
};
match matches.opt_str("r").as_ref().map(|s| &**s) {
Some("rust") | None => {}
Some(s) => {

View File

@ -3,6 +3,7 @@ use std::path::Path;
use std::str;
use errors;
use crate::syntax::feature_gate::UnstableFeatures;
use crate::syntax::edition::Edition;
use crate::html::markdown::{IdMap, ErrorCodes, Markdown};
use std::cell::RefCell;
@ -23,7 +24,7 @@ pub struct ExternalHtml {
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler,
id_map: &mut IdMap)
id_map: &mut IdMap, edition: Edition)
-> Option<ExternalHtml> {
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
load_external_files(in_header, diag)
@ -34,7 +35,8 @@ impl ExternalHtml {
.and_then(|(ih, bc)|
load_external_files(md_before_content, diag)
.map(|m_bc| (ih,
format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), codes))))
format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map),
codes, edition))))
)
.and_then(|(ih, bc)|
load_external_files(after_content, diag)
@ -43,7 +45,8 @@ impl ExternalHtml {
.and_then(|(ih, bc, ac)|
load_external_files(md_after_content, diag)
.map(|m_ac| (ih, bc,
format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), codes))))
format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map),
codes, edition))))
)
.map(|(ih, bc, ac)|
ExternalHtml {

View File

@ -42,14 +42,21 @@ fn opts() -> Options {
/// A unit struct which has the `fmt::Display` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
/// The second parameter is a list of link replacements
///
/// The second parameter is a list of link replacements.
///
/// The third is the current list of used header IDs.
///
/// The fourth is whether to allow the use of explicit error codes in doctest lang strings.
///
/// The fifth is what default edition to use when parsing doctests (to add a `fn main`).
pub struct Markdown<'a>(
pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes);
pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
/// A unit struct like `Markdown`, that renders the markdown with a
/// table of contents.
pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
/// A unit struct like `Markdown`, that renders only the first paragraph.
pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]);
@ -146,13 +153,15 @@ thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> =
struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
inner: I,
check_error_codes: ErrorCodes,
edition: Edition,
}
impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
fn new(iter: I, error_codes: ErrorCodes) -> Self {
fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self {
CodeBlocks {
inner: iter,
check_error_codes: error_codes,
edition,
}
}
}
@ -177,6 +186,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
return event;
}
let explicit_edition = edition.is_some();
let edition = edition.unwrap_or(self.edition);
let mut origtext = String::new();
for event in &mut self.inner {
match event {
@ -202,22 +214,14 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
.collect::<Vec<Cow<'_, str>>>().join("\n");
let krate = krate.as_ref().map(|s| &**s);
let (test, _) = test::make_test(&test, krate, false,
&Default::default());
&Default::default(), edition);
let channel = if test.contains("#![feature(") {
"&amp;version=nightly"
} else {
""
};
let edition_string = if let Some(e @ Edition::Edition2018) = edition {
format!("&amp;edition={}{}", e,
if channel == "&amp;version=nightly" { "" }
else { "&amp;version=nightly" })
} else if let Some(e) = edition {
format!("&amp;edition={}", e)
} else {
"".to_owned()
};
let edition_string = format!("&amp;edition={}", edition);
// These characters don't need to be escaped in a URI.
// FIXME: use a library function for percent encoding.
@ -247,8 +251,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
Some(("This example is not tested".to_owned(), "ignore"))
} else if compile_fail {
Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
} else if let Some(e) = edition {
Some((format!("This code runs with edition {}", e), "edition"))
} else if explicit_edition {
Some((format!("This code runs with edition {}", edition), "edition"))
} else {
None
};
@ -259,7 +263,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
Some(&format!("rust-example-rendered{}",
if ignore { " ignore" }
else if compile_fail { " compile_fail" }
else if edition.is_some() { " edition " }
else if explicit_edition { " edition " }
else { "" })),
playground_button.as_ref().map(String::as_str),
Some((s1.as_str(), s2))));
@ -270,7 +274,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
Some(&format!("rust-example-rendered{}",
if ignore { " ignore" }
else if compile_fail { " compile_fail" }
else if edition.is_some() { " edition " }
else if explicit_edition { " edition " }
else { "" })),
playground_button.as_ref().map(String::as_str),
None));
@ -659,7 +663,7 @@ impl LangString {
impl<'a> fmt::Display for Markdown<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let Markdown(md, links, ref ids, codes) = *self;
let Markdown(md, links, ref ids, codes, edition) = *self;
let mut ids = ids.borrow_mut();
// This is actually common enough to special-case
@ -678,7 +682,7 @@ impl<'a> fmt::Display for Markdown<'a> {
let p = HeadingLinks::new(p, None, &mut ids);
let p = LinkReplacer::new(p, links);
let p = CodeBlocks::new(p, codes);
let p = CodeBlocks::new(p, codes, edition);
let p = Footnotes::new(p);
html::push_html(&mut s, p);
@ -688,7 +692,7 @@ impl<'a> fmt::Display for Markdown<'a> {
impl<'a> fmt::Display for MarkdownWithToc<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let MarkdownWithToc(md, ref ids, codes) = *self;
let MarkdownWithToc(md, ref ids, codes, edition) = *self;
let mut ids = ids.borrow_mut();
let p = Parser::new_ext(md, opts());
@ -699,7 +703,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
{
let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
let p = CodeBlocks::new(p, codes);
let p = CodeBlocks::new(p, codes, edition);
let p = Footnotes::new(p);
html::push_html(&mut s, p);
}
@ -712,7 +716,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
impl<'a> fmt::Display for MarkdownHtml<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let MarkdownHtml(md, ref ids, codes) = *self;
let MarkdownHtml(md, ref ids, codes, edition) = *self;
let mut ids = ids.borrow_mut();
// This is actually common enough to special-case
@ -728,7 +732,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
let mut s = String::with_capacity(md.len() * 3 / 2);
let p = HeadingLinks::new(p, None, &mut ids);
let p = CodeBlocks::new(p, codes);
let p = CodeBlocks::new(p, codes, edition);
let p = Footnotes::new(p);
html::push_html(&mut s, p);

View File

@ -47,6 +47,7 @@ use std::rc::Rc;
use errors;
use serialize::json::{ToJson, Json, as_json};
use syntax::ast;
use syntax::edition::Edition;
use syntax::ext::base::MacroKind;
use syntax::source_map::FileName;
use syntax::feature_gate::UnstableFeatures;
@ -107,6 +108,8 @@ struct Context {
/// publicly reused items to redirect to the right location.
pub render_redirect_pages: bool,
pub codes: ErrorCodes,
/// The default edition used to parse doctests.
pub edition: Edition,
/// The map used to ensure all generated 'id=' attributes are unique.
id_map: Rc<RefCell<IdMap>>,
pub shared: Arc<SharedContext>,
@ -513,7 +516,8 @@ pub fn run(mut krate: clean::Crate,
options: RenderOptions,
passes: FxHashSet<String>,
renderinfo: RenderInfo,
diag: &errors::Handler) -> Result<(), Error> {
diag: &errors::Handler,
edition: Edition) -> Result<(), Error> {
// need to save a copy of the options for rendering the index page
let md_opts = options.clone();
let RenderOptions {
@ -603,6 +607,7 @@ pub fn run(mut krate: clean::Crate,
dst,
render_redirect_pages: false,
codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
edition,
id_map: Rc::new(RefCell::new(id_map)),
shared: Arc::new(scx),
};
@ -1127,7 +1132,7 @@ themePicker.onblur = handleThemeButtonsBlur;
md_opts.output = cx.dst.clone();
md_opts.external_html = (*cx.shared).layout.external_html.clone();
crate::markdown::render(index_page, md_opts, diag);
crate::markdown::render(index_page, md_opts, diag, cx.edition);
} else {
let dst = cx.dst.join("index.html");
let mut w = BufWriter::new(try_err!(File::create(&dst), &dst));
@ -2552,7 +2557,7 @@ fn render_markdown(w: &mut fmt::Formatter<'_>,
if is_hidden { " hidden" } else { "" },
prefix,
Markdown(md_text, &links, RefCell::new(&mut ids),
cx.codes))
cx.codes, cx.edition))
}
fn document_short(
@ -2917,7 +2922,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
if let Some(note) = note {
let mut ids = cx.id_map.borrow_mut();
let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes);
let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes, cx.edition);
message.push_str(&format!(": {}", html));
}
stability.push(format!("<div class='stab deprecated'>{}</div>", message));
@ -2966,7 +2971,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
message = format!(
"<details><summary>{}</summary>{}</details>",
message,
MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes)
MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition)
);
}
@ -4179,7 +4184,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
let mut ids = cx.id_map.borrow_mut();
write!(w, "<div class='docblock'>{}</div>",
Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?;
Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids),
cx.codes, cx.edition))?;
}
}

View File

@ -391,7 +391,10 @@ fn main_args(args: &[String]) -> i32 {
match (options.should_test, options.markdown_input()) {
(true, true) => return markdown::test(options, &diag),
(true, false) => return test::run(options),
(false, true) => return markdown::render(options.input, options.render_options, &diag),
(false, true) => return markdown::render(options.input,
options.render_options,
&diag,
options.edition),
(false, false) => {}
}
@ -399,7 +402,8 @@ fn main_args(args: &[String]) -> i32 {
// but we can't crates the Handler ahead of time because it's not Send
let diag_opts = (options.error_format,
options.debugging_options.treat_err_as_bug,
options.debugging_options.ui_testing);
options.debugging_options.ui_testing,
options.edition);
let show_coverage = options.show_coverage;
rust_input(options, move |out| {
if show_coverage {
@ -410,7 +414,7 @@ fn main_args(args: &[String]) -> i32 {
let Output { krate, passes, renderinfo, renderopts } = out;
info!("going to format");
let (error_format, treat_err_as_bug, ui_testing) = diag_opts;
let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts;
let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
match html::render::run(
krate,
@ -418,6 +422,7 @@ fn main_args(args: &[String]) -> i32 {
passes.into_iter().collect(),
renderinfo,
&diag,
edition,
) {
Ok(_) => rustc_driver::EXIT_SUCCESS,
Err(e) => {

View File

@ -5,6 +5,7 @@ use std::cell::RefCell;
use errors;
use testing;
use syntax::edition::Edition;
use syntax::source_map::DUMMY_SP;
use syntax::feature_gate::UnstableFeatures;
@ -36,7 +37,12 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
/// Render `input` (e.g., "foo.md") into an HTML file in `output`
/// (e.g., output = "bar" => "bar/foo.html").
pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> i32 {
pub fn render(
input: PathBuf,
options: RenderOptions,
diag: &errors::Handler,
edition: Edition
) -> i32 {
let mut output = options.output;
output.push(input.file_stem().unwrap());
output.set_extension("html");
@ -76,9 +82,9 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) ->
let mut ids = IdMap::new();
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let text = if !options.markdown_no_toc {
MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string()
MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string()
} else {
Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string()
Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string()
};
let err = write!(

View File

@ -167,7 +167,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
maybe_sysroot: Option<PathBuf>, linker: Option<PathBuf>, edition: Edition,
persist_doctests: Option<PathBuf>) {
let (test, line_offset) = match panic::catch_unwind(|| {
make_test(test, Some(cratename), as_test_harness, opts)
make_test(test, Some(cratename), as_test_harness, opts, edition)
}) {
Ok((test, line_offset)) => (test, line_offset),
Err(cause) if cause.is::<errors::FatalErrorMarker>() => {
@ -356,7 +356,8 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
pub fn make_test(s: &str,
cratename: Option<&str>,
dont_insert_main: bool,
opts: &TestOptions)
opts: &TestOptions,
edition: Edition)
-> (String, usize) {
let (crate_attrs, everything_else, crates) = partition_source(s);
let everything_else = everything_else.trim();
@ -390,6 +391,8 @@ pub fn make_test(s: &str,
use errors::emitter::EmitterWriter;
use errors::Handler;
syntax::ext::hygiene::set_default_edition(edition);
let filename = FileName::anon_source_code(s);
let source = crates + &everything_else;
@ -397,6 +400,7 @@ pub fn make_test(s: &str,
// send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = EmitterWriter::new(box io::sink(), None, false, false, false);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
let handler = Handler::with_emitter(false, None, box emitter);
let sess = ParseSess::with_span_handler(handler, cm);

View File

@ -15,6 +15,7 @@ use std::path::Path;
use std::path::PathBuf;
use std::cell::RefCell;
use syntax::edition::DEFAULT_EDITION;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND};
@ -97,7 +98,8 @@ impl Formatter for HTMLFormatter {
Some(ref desc) => {
let mut id_map = self.0.borrow_mut();
write!(output, "{}",
Markdown(desc, &[], RefCell::new(&mut id_map), ErrorCodes::Yes))?
Markdown(desc, &[], RefCell::new(&mut id_map),
ErrorCodes::Yes, DEFAULT_EDITION))?
},
None => write!(output, "<p>No description.</p>\n")?,
}