Skip to content

Commit 357445b

Browse files
notriddleGuillaumeGomez
authored andcommitted
Fix backslashes and line breaks in footnote lint
1 parent 02f75ab commit 357445b

3 files changed

Lines changed: 89 additions & 7 deletions

File tree

src/librustdoc/passes/lint/footnotes.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
2323
match event {
2424
Event::Text(text)
2525
if &*text == "["
26-
&& let Some((Event::Text(text), _)) = parser.peek()
27-
&& text.trim_start().starts_with('^')
28-
&& parser.next().is_some()
29-
&& let Some((Event::Text(text), end_span)) = parser.peek()
30-
&& &**text == "]" =>
26+
&& (span.start == 0 || dox.as_bytes().get(span.start - 1) != Some(&b'\\'))
27+
&& let Some(len) = scan_footnote_ref(&dox[span.start..]) =>
3128
{
32-
missing_footnote_references.insert(Range { start: span.start, end: end_span.end });
29+
missing_footnote_references
30+
.insert(Range { start: span.start, end: span.start + len });
3331
}
3432
Event::FootnoteReference(label) => {
3533
footnote_references.insert(label);
@@ -85,3 +83,35 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
8583
);
8684
}
8785
}
86+
87+
fn scan_footnote_ref(dox: &str) -> Option<usize> {
88+
let dox = dox.as_bytes();
89+
let mut i = 0;
90+
if dox.get(i) != Some(&b'[') {
91+
return None;
92+
}
93+
i += 1;
94+
if dox.get(i) != Some(&b'^') {
95+
return None;
96+
}
97+
i += 1;
98+
while let Some(&c) = dox.get(i) {
99+
if c == b']' {
100+
i += 1;
101+
return Some(i);
102+
}
103+
if c == b'\r' || c == b'\n' || c == b'[' {
104+
// Can't nest things like this.
105+
break;
106+
}
107+
if c == b'\\' {
108+
i += 1;
109+
}
110+
if dox.get(i) == Some(&b'\r') || dox.get(i) == Some(&b'\n') {
111+
// Can't have line breaks in footnote refs
112+
break;
113+
}
114+
i += 1;
115+
}
116+
None
117+
}

tests/rustdoc-ui/lints/broken-footnote.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,31 @@
1414
//! [^1]: bar
1515
//!
1616
//! ```
17+
18+
// Edge cases from https://pulldown-cmark.github.io/pulldown-cmark/specs/footnotes.html
19+
/// The following are not footnote references:
20+
///
21+
/// \[^a]
22+
///
23+
/// [\^b]
24+
///
25+
/// [^c\]
26+
///
27+
/// [^d
28+
/// e]
29+
///
30+
/// [^f\
31+
/// g]
32+
pub struct NotReferences;
33+
34+
/// The following are not footnote references:
35+
///
36+
/// [^a b]
37+
//~^ ERROR: no footnote definition matching this footnote
38+
///
39+
/// [^1\.2]
40+
//~^ ERROR: no footnote definition matching this footnote
41+
///
42+
/// [^*]
43+
//~^ ERROR: no footnote definition matching this footnote
44+
pub struct EdgeCases;

tests/rustdoc-ui/lints/broken-footnote.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,29 @@ LL | //! Footnote referenced [^1]. And [^2]. And [^bla].
2020
| |
2121
| help: if it should not be a footnote, escape it: `\`
2222

23-
error: aborting due to 2 previous errors
23+
error: no footnote definition matching this footnote
24+
--> $DIR/broken-footnote.rs:39:5
25+
|
26+
LL | /// [^1\.2]
27+
| -^^^^^^
28+
| |
29+
| help: if it should not be a footnote, escape it: `\`
30+
31+
error: no footnote definition matching this footnote
32+
--> $DIR/broken-footnote.rs:42:5
33+
|
34+
LL | /// [^*]
35+
| -^^^
36+
| |
37+
| help: if it should not be a footnote, escape it: `\`
38+
39+
error: no footnote definition matching this footnote
40+
--> $DIR/broken-footnote.rs:36:5
41+
|
42+
LL | /// [^a b]
43+
| -^^^^^
44+
| |
45+
| help: if it should not be a footnote, escape it: `\`
46+
47+
error: aborting due to 5 previous errors
2448

0 commit comments

Comments
 (0)