Auto merge of #13010 - notriddle:notriddle/unbalanced-ticks-backslash, r=blyxyas

doc_markdown: detect escaped `` ` `` when checking unmatched

```
changelog: [`doc_markdown`]: correctly detect backslash-escaped `` ` ``
```
This commit is contained in:
bors 2024-07-02 21:30:36 +00:00
commit 3af20058eb
3 changed files with 46 additions and 2 deletions

View file

@ -769,7 +769,18 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
TaskListMarker(_) | Code(_) | Rule => (), TaskListMarker(_) | Code(_) | Rule => (),
FootnoteReference(text) | Text(text) => { FootnoteReference(text) | Text(text) => {
paragraph_range.end = range.end; paragraph_range.end = range.end;
ticks_unbalanced |= text.contains('`') && !in_code; let range_ = range.clone();
ticks_unbalanced |= text.contains('`')
&& !in_code
&& doc[range.clone()].bytes().enumerate().any(|(i, c)| {
// scan the markdown source code bytes for backquotes that aren't preceded by backslashes
// - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii)
// - relevant backquotes are within doc[range], but backslashes are not, because they're not
// actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes)
// - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in
// usize, that would underflow and maybe panic
c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\'))
});
if Some(&text) == in_link.as_ref() || ticks_unbalanced { if Some(&text) == in_link.as_ref() || ticks_unbalanced {
// Probably a link of the form `<http://example.com>` // Probably a link of the form `<http://example.com>`
// Which are represented as a link to "http://example.com" with // Which are represented as a link to "http://example.com" with

View file

@ -49,3 +49,20 @@ fn other_markdown() {}
/// pub struct Struct; /// pub struct Struct;
/// ``` /// ```
fn issue_7421() {} fn issue_7421() {}
/// `
//~^ ERROR: backticks are unbalanced
fn escape_0() {}
/// Escaped \` backticks don't count.
fn escape_1() {}
/// Escaped \` \` backticks don't count.
fn escape_2() {}
/// Escaped \` ` backticks don't count, but unescaped backticks do.
//~^ ERROR: backticks are unbalanced
fn escape_3() {}
/// Backslashes ` \` within code blocks don't count.
fn escape_4() {}

View file

@ -78,5 +78,21 @@ help: try
LL | /// - This item needs `backticks_here` LL | /// - This item needs `backticks_here`
| ~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~
error: aborting due to 8 previous errors error: backticks are unbalanced
--> tests/ui/doc/unbalanced_ticks.rs:53:5
|
LL | /// `
| ^
|
= help: a backtick may be missing a pair
error: backticks are unbalanced
--> tests/ui/doc/unbalanced_ticks.rs:63:5
|
LL | /// Escaped \` ` backticks don't count, but unescaped backticks do.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: a backtick may be missing a pair
error: aborting due to 10 previous errors