Skip to content

Commit 3af2005

Browse files
committed
Auto merge of rust-lang#13010 - notriddle:notriddle/unbalanced-ticks-backslash, r=blyxyas
doc_markdown: detect escaped `` ` `` when checking unmatched ``` changelog: [`doc_markdown`]: correctly detect backslash-escaped `` ` `` ```
2 parents 6e6683b + 70c8579 commit 3af2005

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

clippy_lints/src/doc/mod.rs

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

tests/ui/doc/unbalanced_ticks.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,20 @@ fn other_markdown() {}
4949
/// pub struct Struct;
5050
/// ```
5151
fn issue_7421() {}
52+
53+
/// `
54+
//~^ ERROR: backticks are unbalanced
55+
fn escape_0() {}
56+
57+
/// Escaped \` backticks don't count.
58+
fn escape_1() {}
59+
60+
/// Escaped \` \` backticks don't count.
61+
fn escape_2() {}
62+
63+
/// Escaped \` ` backticks don't count, but unescaped backticks do.
64+
//~^ ERROR: backticks are unbalanced
65+
fn escape_3() {}
66+
67+
/// Backslashes ` \` within code blocks don't count.
68+
fn escape_4() {}

tests/ui/doc/unbalanced_ticks.stderr

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,21 @@ help: try
7878
LL | /// - This item needs `backticks_here`
7979
| ~~~~~~~~~~~~~~~~
8080

81-
error: aborting due to 8 previous errors
81+
error: backticks are unbalanced
82+
--> tests/ui/doc/unbalanced_ticks.rs:53:5
83+
|
84+
LL | /// `
85+
| ^
86+
|
87+
= help: a backtick may be missing a pair
88+
89+
error: backticks are unbalanced
90+
--> tests/ui/doc/unbalanced_ticks.rs:63:5
91+
|
92+
LL | /// Escaped \` ` backticks don't count, but unescaped backticks do.
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
94+
|
95+
= help: a backtick may be missing a pair
96+
97+
error: aborting due to 10 previous errors
8298

0 commit comments

Comments
 (0)