mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Don't emit an error if the custom_code_classes_in_docs
feature is disabled when its syntax is used.
This commit is contained in:
parent
cdd182cbb2
commit
e1294b26af
@ -1243,6 +1243,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
|
||||
def_id.to_def_id(),
|
||||
span_of_fragments(&attrs.doc_strings).unwrap_or(sp),
|
||||
)),
|
||||
self.tcx.features().custom_code_classes_in_docs,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,8 @@ impl ExternalHtml {
|
||||
edition,
|
||||
playground,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
// For external files, it'll be disabled until the feature is enabled by default.
|
||||
custom_code_classes_in_docs: false,
|
||||
}
|
||||
.into_string()
|
||||
);
|
||||
@ -61,6 +63,8 @@ impl ExternalHtml {
|
||||
edition,
|
||||
playground,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
// For external files, it'll be disabled until the feature is enabled by default.
|
||||
custom_code_classes_in_docs: false,
|
||||
}
|
||||
.into_string()
|
||||
);
|
||||
|
@ -20,6 +20,7 @@
|
||||
//! edition: Edition::Edition2015,
|
||||
//! playground: &None,
|
||||
//! heading_offset: HeadingOffset::H2,
|
||||
//! custom_code_classes_in_docs: true,
|
||||
//! };
|
||||
//! let html = md.into_string();
|
||||
//! // ... something using html
|
||||
@ -95,6 +96,8 @@ pub struct Markdown<'a> {
|
||||
/// Offset at which we render headings.
|
||||
/// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
|
||||
pub heading_offset: HeadingOffset,
|
||||
/// `true` if the `custom_code_classes_in_docs` feature is enabled.
|
||||
pub custom_code_classes_in_docs: bool,
|
||||
}
|
||||
/// A struct like `Markdown` that renders the markdown with a table of contents.
|
||||
pub(crate) struct MarkdownWithToc<'a> {
|
||||
@ -103,6 +106,8 @@ pub(crate) struct MarkdownWithToc<'a> {
|
||||
pub(crate) error_codes: ErrorCodes,
|
||||
pub(crate) edition: Edition,
|
||||
pub(crate) playground: &'a Option<Playground>,
|
||||
/// `true` if the `custom_code_classes_in_docs` feature is enabled.
|
||||
pub(crate) custom_code_classes_in_docs: bool,
|
||||
}
|
||||
/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags
|
||||
/// and includes no paragraph tags.
|
||||
@ -203,6 +208,7 @@ struct CodeBlocks<'p, 'a, I: Iterator<Item = Event<'a>>> {
|
||||
// Information about the playground if a URL has been specified, containing an
|
||||
// optional crate name and the URL.
|
||||
playground: &'p Option<Playground>,
|
||||
custom_code_classes_in_docs: bool,
|
||||
}
|
||||
|
||||
impl<'p, 'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'p, 'a, I> {
|
||||
@ -211,8 +217,15 @@ impl<'p, 'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'p, 'a, I> {
|
||||
error_codes: ErrorCodes,
|
||||
edition: Edition,
|
||||
playground: &'p Option<Playground>,
|
||||
custom_code_classes_in_docs: bool,
|
||||
) -> Self {
|
||||
CodeBlocks { inner: iter, check_error_codes: error_codes, edition, playground }
|
||||
CodeBlocks {
|
||||
inner: iter,
|
||||
check_error_codes: error_codes,
|
||||
edition,
|
||||
playground,
|
||||
custom_code_classes_in_docs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,8 +255,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
||||
|
||||
let parse_result = match kind {
|
||||
CodeBlockKind::Fenced(ref lang) => {
|
||||
let parse_result =
|
||||
LangString::parse_without_check(lang, self.check_error_codes, false);
|
||||
let parse_result = LangString::parse_without_check(
|
||||
lang,
|
||||
self.check_error_codes,
|
||||
false,
|
||||
self.custom_code_classes_in_docs,
|
||||
);
|
||||
if !parse_result.rust {
|
||||
let added_classes = parse_result.added_classes;
|
||||
let lang_string = if let Some(lang) = parse_result.unknown.first() {
|
||||
@ -725,8 +742,17 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
|
||||
error_codes: ErrorCodes,
|
||||
enable_per_target_ignores: bool,
|
||||
extra_info: Option<&ExtraInfo<'_>>,
|
||||
custom_code_classes_in_docs: bool,
|
||||
) {
|
||||
find_codes(doc, tests, error_codes, enable_per_target_ignores, extra_info, false)
|
||||
find_codes(
|
||||
doc,
|
||||
tests,
|
||||
error_codes,
|
||||
enable_per_target_ignores,
|
||||
extra_info,
|
||||
false,
|
||||
custom_code_classes_in_docs,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn find_codes<T: doctest::Tester>(
|
||||
@ -736,6 +762,7 @@ pub(crate) fn find_codes<T: doctest::Tester>(
|
||||
enable_per_target_ignores: bool,
|
||||
extra_info: Option<&ExtraInfo<'_>>,
|
||||
include_non_rust: bool,
|
||||
custom_code_classes_in_docs: bool,
|
||||
) {
|
||||
let mut parser = Parser::new(doc).into_offset_iter();
|
||||
let mut prev_offset = 0;
|
||||
@ -754,6 +781,7 @@ pub(crate) fn find_codes<T: doctest::Tester>(
|
||||
error_codes,
|
||||
enable_per_target_ignores,
|
||||
extra_info,
|
||||
custom_code_classes_in_docs,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1153,8 +1181,15 @@ impl LangString {
|
||||
string: &str,
|
||||
allow_error_code_check: ErrorCodes,
|
||||
enable_per_target_ignores: bool,
|
||||
custom_code_classes_in_docs: bool,
|
||||
) -> Self {
|
||||
Self::parse(string, allow_error_code_check, enable_per_target_ignores, None)
|
||||
Self::parse(
|
||||
string,
|
||||
allow_error_code_check,
|
||||
enable_per_target_ignores,
|
||||
None,
|
||||
custom_code_classes_in_docs,
|
||||
)
|
||||
}
|
||||
|
||||
fn parse(
|
||||
@ -1162,6 +1197,7 @@ impl LangString {
|
||||
allow_error_code_check: ErrorCodes,
|
||||
enable_per_target_ignores: bool,
|
||||
extra: Option<&ExtraInfo<'_>>,
|
||||
custom_code_classes_in_docs: bool,
|
||||
) -> Self {
|
||||
let allow_error_code_check = allow_error_code_check.as_bool();
|
||||
let mut seen_rust_tags = false;
|
||||
@ -1197,7 +1233,11 @@ impl LangString {
|
||||
seen_rust_tags = true;
|
||||
}
|
||||
LangStringToken::LangToken("custom") => {
|
||||
seen_custom_tag = true;
|
||||
if custom_code_classes_in_docs {
|
||||
seen_custom_tag = true;
|
||||
} else {
|
||||
seen_other_tags = true;
|
||||
}
|
||||
}
|
||||
LangStringToken::LangToken("test_harness") => {
|
||||
data.test_harness = true;
|
||||
@ -1268,11 +1308,16 @@ impl LangString {
|
||||
data.unknown.push(x.to_owned());
|
||||
}
|
||||
LangStringToken::KeyValueAttribute(key, value) => {
|
||||
if key == "class" {
|
||||
data.added_classes.push(value.to_owned());
|
||||
} else if let Some(extra) = extra {
|
||||
extra
|
||||
.error_invalid_codeblock_attr(format!("unsupported attribute `{key}`"));
|
||||
if custom_code_classes_in_docs {
|
||||
if key == "class" {
|
||||
data.added_classes.push(value.to_owned());
|
||||
} else if let Some(extra) = extra {
|
||||
extra.error_invalid_codeblock_attr(format!(
|
||||
"unsupported attribute `{key}`"
|
||||
));
|
||||
}
|
||||
} else {
|
||||
seen_other_tags = true;
|
||||
}
|
||||
}
|
||||
LangStringToken::ClassAttribute(class) => {
|
||||
@ -1302,6 +1347,7 @@ impl Markdown<'_> {
|
||||
edition,
|
||||
playground,
|
||||
heading_offset,
|
||||
custom_code_classes_in_docs,
|
||||
} = self;
|
||||
|
||||
// This is actually common enough to special-case
|
||||
@ -1324,7 +1370,7 @@ impl Markdown<'_> {
|
||||
let p = Footnotes::new(p);
|
||||
let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
|
||||
let p = TableWrapper::new(p);
|
||||
let p = CodeBlocks::new(p, codes, edition, playground);
|
||||
let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs);
|
||||
html::push_html(&mut s, p);
|
||||
|
||||
s
|
||||
@ -1333,7 +1379,14 @@ impl Markdown<'_> {
|
||||
|
||||
impl MarkdownWithToc<'_> {
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
|
||||
let MarkdownWithToc {
|
||||
content: md,
|
||||
ids,
|
||||
error_codes: codes,
|
||||
edition,
|
||||
playground,
|
||||
custom_code_classes_in_docs,
|
||||
} = self;
|
||||
|
||||
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
|
||||
|
||||
@ -1345,7 +1398,7 @@ impl MarkdownWithToc<'_> {
|
||||
let p = HeadingLinks::new(p, Some(&mut toc), ids, HeadingOffset::H1);
|
||||
let p = Footnotes::new(p);
|
||||
let p = TableWrapper::new(p.map(|(ev, _)| ev));
|
||||
let p = CodeBlocks::new(p, codes, edition, playground);
|
||||
let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs);
|
||||
html::push_html(&mut s, p);
|
||||
}
|
||||
|
||||
@ -1786,7 +1839,11 @@ pub(crate) struct RustCodeBlock {
|
||||
|
||||
/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
|
||||
/// untagged (and assumed to be rust).
|
||||
pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeBlock> {
|
||||
pub(crate) fn rust_code_blocks(
|
||||
md: &str,
|
||||
extra_info: &ExtraInfo<'_>,
|
||||
custom_code_classes_in_docs: bool,
|
||||
) -> Vec<RustCodeBlock> {
|
||||
let mut code_blocks = vec![];
|
||||
|
||||
if md.is_empty() {
|
||||
@ -1803,7 +1860,13 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
|
||||
let lang_string = if syntax.is_empty() {
|
||||
Default::default()
|
||||
} else {
|
||||
LangString::parse(&*syntax, ErrorCodes::Yes, false, Some(extra_info))
|
||||
LangString::parse(
|
||||
&*syntax,
|
||||
ErrorCodes::Yes,
|
||||
false,
|
||||
Some(extra_info),
|
||||
custom_code_classes_in_docs,
|
||||
)
|
||||
};
|
||||
if !lang_string.rust {
|
||||
continue;
|
||||
|
@ -403,7 +403,8 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
|
||||
error_codes: shared.codes,
|
||||
edition: shared.edition(),
|
||||
playground: &shared.playground,
|
||||
heading_offset: HeadingOffset::H1
|
||||
heading_offset: HeadingOffset::H1,
|
||||
custom_code_classes_in_docs: false,
|
||||
}
|
||||
.into_string()
|
||||
)
|
||||
@ -437,6 +438,7 @@ fn render_markdown<'a, 'cx: 'a>(
|
||||
heading_offset: HeadingOffset,
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs;
|
||||
write!(
|
||||
f,
|
||||
"<div class=\"docblock\">{}</div>",
|
||||
@ -448,6 +450,7 @@ fn render_markdown<'a, 'cx: 'a>(
|
||||
edition: cx.shared.edition(),
|
||||
playground: &cx.shared.playground,
|
||||
heading_offset,
|
||||
custom_code_classes_in_docs,
|
||||
}
|
||||
.into_string()
|
||||
)
|
||||
@ -1778,6 +1781,7 @@ fn render_impl(
|
||||
</div>",
|
||||
);
|
||||
}
|
||||
let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs;
|
||||
write!(
|
||||
w,
|
||||
"<div class=\"docblock\">{}</div>",
|
||||
@ -1788,7 +1792,8 @@ fn render_impl(
|
||||
error_codes: cx.shared.codes,
|
||||
edition: cx.shared.edition(),
|
||||
playground: &cx.shared.playground,
|
||||
heading_offset: HeadingOffset::H4
|
||||
heading_offset: HeadingOffset::H4,
|
||||
custom_code_classes_in_docs,
|
||||
}
|
||||
.into_string()
|
||||
);
|
||||
|
@ -80,6 +80,8 @@ pub(crate) fn render<P: AsRef<Path>>(
|
||||
error_codes,
|
||||
edition,
|
||||
playground: &playground,
|
||||
// For markdown files, it'll be disabled until the feature is enabled by default.
|
||||
custom_code_classes_in_docs: false,
|
||||
}
|
||||
.into_string()
|
||||
} else {
|
||||
@ -91,6 +93,8 @@ pub(crate) fn render<P: AsRef<Path>>(
|
||||
edition,
|
||||
playground: &playground,
|
||||
heading_offset: HeadingOffset::H1,
|
||||
// For markdown files, it'll be disabled until the feature is enabled by default.
|
||||
custom_code_classes_in_docs: false,
|
||||
}
|
||||
.into_string()
|
||||
};
|
||||
@ -154,7 +158,15 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
|
||||
collector.set_position(DUMMY_SP);
|
||||
let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
|
||||
|
||||
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
|
||||
// For markdown files, it'll be disabled until the feature is enabled by default.
|
||||
find_testable_code(
|
||||
&input_str,
|
||||
&mut collector,
|
||||
codes,
|
||||
options.enable_per_target_ignores,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
|
||||
crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
|
||||
Ok(())
|
||||
|
@ -208,7 +208,14 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
|
||||
let has_docs = !i.attrs.doc_strings.is_empty();
|
||||
let mut tests = Tests { found_tests: 0 };
|
||||
|
||||
find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, false, None);
|
||||
find_testable_code(
|
||||
&i.doc_value(),
|
||||
&mut tests,
|
||||
ErrorCodes::No,
|
||||
false,
|
||||
None,
|
||||
self.ctx.tcx.features().custom_code_classes_in_docs,
|
||||
);
|
||||
|
||||
let has_doc_example = tests.found_tests != 0;
|
||||
let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
|
||||
|
@ -9,7 +9,9 @@ use crate::core::DocContext;
|
||||
use crate::fold::DocFolder;
|
||||
use crate::html::markdown::{find_codes, ErrorCodes, LangString};
|
||||
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_errors::StashKey;
|
||||
use rustc_feature::GateIssue;
|
||||
use rustc_session::parse::add_feature_diagnostics_for_issue;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
pub(crate) const CHECK_CUSTOM_CODE_CLASSES: Pass = Pass {
|
||||
@ -55,23 +57,32 @@ pub(crate) fn look_for_custom_classes<'tcx>(cx: &DocContext<'tcx>, item: &Item)
|
||||
let mut tests = TestsWithCustomClasses { custom_classes_found: vec![] };
|
||||
|
||||
let dox = item.attrs.doc_value();
|
||||
find_codes(&dox, &mut tests, ErrorCodes::No, false, None, true);
|
||||
find_codes(&dox, &mut tests, ErrorCodes::No, false, None, true, true);
|
||||
|
||||
if !tests.custom_classes_found.is_empty() && !cx.tcx.features().custom_code_classes_in_docs {
|
||||
feature_err(
|
||||
&cx.tcx.sess.parse_sess,
|
||||
let span = item.attr_span(cx.tcx);
|
||||
let sess = &cx.tcx.sess.parse_sess;
|
||||
let mut err = sess
|
||||
.span_diagnostic
|
||||
.struct_span_warn(span, "custom classes in code blocks will change behaviour");
|
||||
add_feature_diagnostics_for_issue(
|
||||
&mut err,
|
||||
sess,
|
||||
sym::custom_code_classes_in_docs,
|
||||
item.attr_span(cx.tcx),
|
||||
"custom classes in code blocks are unstable",
|
||||
)
|
||||
.note(
|
||||
GateIssue::Language,
|
||||
false,
|
||||
);
|
||||
|
||||
err.note(
|
||||
// This will list the wrong items to make them more easily searchable.
|
||||
// To ensure the most correct hits, it adds back the 'class:' that was stripped.
|
||||
format!(
|
||||
"found these custom classes: class={}",
|
||||
tests.custom_classes_found.join(",class=")
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
|
||||
// A later feature_err call can steal and cancel this warning.
|
||||
err.stash(span, StashKey::EarlySyntaxWarning);
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,14 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
|
||||
|
||||
let mut tests = Tests { found_tests: 0 };
|
||||
|
||||
find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
|
||||
find_testable_code(
|
||||
dox,
|
||||
&mut tests,
|
||||
ErrorCodes::No,
|
||||
false,
|
||||
None,
|
||||
cx.tcx.features().custom_code_classes_in_docs,
|
||||
);
|
||||
|
||||
if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
|
||||
if should_have_doc_example(cx, item) {
|
||||
|
@ -20,7 +20,9 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
|
||||
if let Some(dox) = &item.opt_doc_value() {
|
||||
let sp = item.attr_span(cx.tcx);
|
||||
let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp);
|
||||
for code_block in markdown::rust_code_blocks(dox, &extra) {
|
||||
for code_block in
|
||||
markdown::rust_code_blocks(dox, &extra, cx.tcx.features().custom_code_classes_in_docs)
|
||||
{
|
||||
check_rust_syntax(cx, item, dox, code_block);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user