rustdoc: remove unportable markdown lint and old parser

Follow up https://github.com/rust-lang/rust/pull/127127
This commit is contained in:
Michael Howell 2025-05-06 10:33:04 -07:00
parent 1a95cc6f9d
commit e648e5b710
7 changed files with 3 additions and 258 deletions

View file

@ -558,7 +558,7 @@ dependencies = [
"if_chain",
"itertools",
"parking_lot",
"pulldown-cmark 0.11.3",
"pulldown-cmark",
"quote",
"regex",
"rustc_tools_util 0.4.2",
@ -2849,17 +2849,6 @@ dependencies = [
"cc",
]
[[package]]
name = "pulldown-cmark"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [
"bitflags",
"memchr",
"unicase",
]
[[package]]
name = "pulldown-cmark"
version = "0.11.3"
@ -4337,7 +4326,7 @@ version = "0.0.0"
dependencies = [
"bitflags",
"itertools",
"pulldown-cmark 0.11.3",
"pulldown-cmark",
"rustc_arena",
"rustc_ast",
"rustc_ast_pretty",
@ -4622,7 +4611,6 @@ dependencies = [
"indexmap",
"itertools",
"minifier",
"pulldown-cmark 0.9.6",
"pulldown-cmark-escape",
"regex",
"rustdoc-json-types",

View file

@ -14,7 +14,6 @@ base64 = "0.21.7"
itertools = "0.12"
indexmap = "2"
minifier = { version = "0.3.5", default-features = false }
pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] }
regex = "1"
rustdoc-json-types = { path = "../rustdoc-json-types" }

View file

@ -196,14 +196,6 @@ declare_rustdoc_lint! {
"detects redundant explicit links in doc comments"
}
declare_rustdoc_lint! {
/// This compatibility lint checks for Markdown syntax that works in the old engine but not
/// the new one.
UNPORTABLE_MARKDOWN,
Warn,
"detects markdown that is interpreted differently in different parser"
}
pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
vec![
BROKEN_INTRA_DOC_LINKS,
@ -217,7 +209,6 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
MISSING_CRATE_LEVEL_DOCS,
UNESCAPED_BACKTICKS,
REDUNDANT_EXPLICIT_LINKS,
UNPORTABLE_MARKDOWN,
]
});
@ -241,4 +232,5 @@ pub(crate) fn register_lints(_sess: &Session, lint_store: &mut LintStore) {
.register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links");
lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls");
lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls");
lint_store.register_removed("rustdoc::unportable_markdown", "old parser removed");
}

View file

@ -6,7 +6,6 @@ mod check_code_block_syntax;
mod html_tags;
mod redundant_explicit_links;
mod unescaped_backticks;
mod unportable_markdown;
use super::Pass;
use crate::clean::*;
@ -49,9 +48,6 @@ impl DocVisitor<'_> for Linter<'_, '_> {
}
if may_have_block_comment_or_html {
html_tags::visit_item(self.cx, item, hir_id, &dox);
unportable_markdown::visit_item(self.cx, item, hir_id, &dox);
} else if may_have_link {
unportable_markdown::visit_item(self.cx, item, hir_id, &dox);
}
}

View file

@ -1,145 +0,0 @@
//! Detects specific markdown syntax that's different between pulldown-cmark
//! 0.9 and 0.11.
//!
//! This is a mitigation for old parser bugs that affected some
//! real crates' docs. The old parser claimed to comply with CommonMark,
//! but it did not. These warnings will eventually be removed,
//! though some of them may become Clippy lints.
//!
//! <https://github.com/rust-lang/rust/pull/121659#issuecomment-1992752820>
//!
//! <https://rustc-dev-guide.rust-lang.org/bug-fix-procedure.html#add-the-lint-to-the-list-of-removed-lists>
use std::collections::{BTreeMap, BTreeSet};
use rustc_hir::HirId;
use rustc_lint_defs::Applicability;
use rustc_resolve::rustdoc::source_span_for_markdown_range;
use {pulldown_cmark as cmarkn, pulldown_cmark_old as cmarko};
use crate::clean::Item;
use crate::core::DocContext;
pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
let tcx = cx.tcx;
// P1: unintended strikethrough was fixed by requiring single-tildes to flank
// the same way underscores do, so nothing is done here
// P2: block quotes without following space parsed wrong
//
// This is the set of starting points for block quotes with no space after
// the `>`. It is populated by the new parser, and if the old parser fails to
// clear it out, it'll produce a warning.
let mut spaceless_block_quotes = BTreeSet::new();
// P3: missing footnote references
//
// This is populated by listening for FootnoteReference from
// the new parser and old parser.
let mut missing_footnote_references = BTreeMap::new();
let mut found_footnote_references = BTreeSet::new();
// populate problem cases from new parser
{
pub fn main_body_opts_new() -> cmarkn::Options {
cmarkn::Options::ENABLE_TABLES
| cmarkn::Options::ENABLE_FOOTNOTES
| cmarkn::Options::ENABLE_STRIKETHROUGH
| cmarkn::Options::ENABLE_TASKLISTS
| cmarkn::Options::ENABLE_SMART_PUNCTUATION
}
let parser_new = cmarkn::Parser::new_ext(dox, main_body_opts_new()).into_offset_iter();
for (event, span) in parser_new {
if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event {
if !dox[span.clone()].starts_with("> ") {
spaceless_block_quotes.insert(span.start);
}
}
if let cmarkn::Event::FootnoteReference(_) = event {
found_footnote_references.insert(span.start + 1);
}
}
}
// remove cases where they don't actually differ
{
pub fn main_body_opts_old() -> cmarko::Options {
cmarko::Options::ENABLE_TABLES
| cmarko::Options::ENABLE_FOOTNOTES
| cmarko::Options::ENABLE_STRIKETHROUGH
| cmarko::Options::ENABLE_TASKLISTS
| cmarko::Options::ENABLE_SMART_PUNCTUATION
}
let parser_old = cmarko::Parser::new_ext(dox, main_body_opts_old()).into_offset_iter();
for (event, span) in parser_old {
if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event
&& !dox[span.clone()].starts_with("> ")
{
spaceless_block_quotes.remove(&span.start);
}
if let cmarko::Event::FootnoteReference(_) = event
&& !found_footnote_references.contains(&(span.start + 1))
{
missing_footnote_references.insert(span.start + 1, span);
}
}
}
for start in spaceless_block_quotes {
let (span, precise) =
source_span_for_markdown_range(tcx, dox, &(start..start + 1), &item.attrs.doc_strings)
.map(|span| (span, true))
.unwrap_or_else(|| (item.attr_span(tcx), false));
tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| {
lint.primary_message("unportable markdown");
lint.help("confusing block quote with no space after the `>` marker".to_string());
if precise {
lint.span_suggestion(
span.shrink_to_hi(),
"if the quote is intended, add a space",
" ",
Applicability::MaybeIncorrect,
);
lint.span_suggestion(
span.shrink_to_lo(),
"if it should not be a quote, escape it",
"\\",
Applicability::MaybeIncorrect,
);
}
});
}
for (_caret, span) in missing_footnote_references {
let (ref_span, precise) =
source_span_for_markdown_range(tcx, dox, &span, &item.attrs.doc_strings)
.map(|span| (span, true))
.unwrap_or_else(|| (item.attr_span(tcx), false));
tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| {
lint.primary_message("unportable markdown");
if precise {
lint.span_suggestion(
ref_span.shrink_to_lo(),
"if it should not be a footnote, escape it",
"\\",
Applicability::MaybeIncorrect,
);
}
if dox.as_bytes().get(span.end) == Some(&b'[') {
lint.help("confusing footnote reference and link");
if precise {
lint.span_suggestion(
ref_span.shrink_to_hi(),
"if the footnote is intended, add a space",
" ",
Applicability::MaybeIncorrect,
);
} else {
lint.help("there should be a space between the link and the footnote");
}
}
});
}
}

View file

@ -1,62 +0,0 @@
// https://internals.rust-lang.org/t/proposal-migrate-the-syntax-of-rustdoc-markdown-footnotes-to-be-compatible-with-the-syntax-used-in-github/18929
//
// A series of test cases for CommonMark corner cases that pulldown-cmark 0.11 fixes.
//
// This version of the lint is targeted at two especially-common cases where docs got broken.
// Other differences in parsing should not warn.
#![allow(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::unportable_markdown)]
/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/654>
///
/// Test footnote [^foot].
///
/// [^foot]: This is nested within the footnote now, but didn't used to be.
///
/// This is a multi-paragraph footnote.
pub struct GfmFootnotes;
/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/773>
///
/// test [^foo][^bar]
///
/// [^foo]: test
/// [^bar]: test2
pub struct FootnoteSmashedName;
/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/829>
///
/// - _t
/// # test
/// t_
pub struct NestingCornerCase;
/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/650>
///
/// *~~__emphasis strike strong__~~* ~~*__strike emphasis strong__*~~
pub struct Emphasis1;
/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/732>
///
/// |
/// |
pub struct NotEnoughTable;
/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/675>
///
/// foo
/// >bar
//~^ ERROR unportable markdown
pub struct BlockQuoteNoSpace;
/// Negative test.
///
/// foo
/// > bar
pub struct BlockQuoteSpace;
/// Negative test.
///
/// >bar
/// baz
pub struct BlockQuoteNoSpaceStart;

View file

@ -1,23 +0,0 @@
error: unportable markdown
--> $DIR/unportable-markdown.rs:48:5
|
LL | /// >bar
| ^
|
= help: confusing block quote with no space after the `>` marker
note: the lint level is defined here
--> $DIR/unportable-markdown.rs:8:9
|
LL | #![deny(rustdoc::unportable_markdown)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: if the quote is intended, add a space
|
LL | /// > bar
| +
help: if it should not be a quote, escape it
|
LL | /// \>bar
| +
error: aborting due to 1 previous error