Skip to content

Commit dd61213

Browse files
authored
Rollup merge of #133040 - GuillaumeGomez:footnote-ref-in-def, r=notriddle
[rustdoc] Fix handling of footnote reference in footnote definition Fixes #131946. We didn't check if we had footnote reference in footnote definition. r? `@notriddle`
2 parents e158303 + 052d40a commit dd61213

File tree

2 files changed

+54
-26
lines changed

2 files changed

+54
-26
lines changed

src/librustdoc/html/markdown/footnotes.rs

+34-26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Markdown footnote handling.
22
use std::fmt::Write as _;
33

4-
use pulldown_cmark::{Event, Tag, TagEnd, html};
4+
use pulldown_cmark::{CowStr, Event, Tag, TagEnd, html};
55
use rustc_data_structures::fx::FxIndexMap;
66

77
use super::SpannedEvent;
@@ -21,7 +21,7 @@ struct FootnoteDef<'a> {
2121
id: usize,
2222
}
2323

24-
impl<'a, 'b, I> Footnotes<'a, 'b, I> {
24+
impl<'a, 'b, I: Iterator<Item = SpannedEvent<'a>>> Footnotes<'a, 'b, I> {
2525
pub(super) fn new(iter: I, existing_footnotes: &'b mut usize) -> Self {
2626
Footnotes { inner: iter, footnotes: FxIndexMap::default(), existing_footnotes }
2727
}
@@ -34,31 +34,50 @@ impl<'a, 'b, I> Footnotes<'a, 'b, I> {
3434
// Don't allow changing the ID of existing entrys, but allow changing the contents.
3535
(content, *id)
3636
}
37+
38+
fn handle_footnote_reference(&mut self, reference: &CowStr<'a>) -> Event<'a> {
39+
// When we see a reference (to a footnote we may not know) the definition of,
40+
// reserve a number for it, and emit a link to that number.
41+
let (_, id) = self.get_entry(reference);
42+
let reference = format!(
43+
"<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{1}</a></sup>",
44+
id,
45+
// Although the ID count is for the whole page, the footnote reference
46+
// are local to the item so we make this ID "local" when displayed.
47+
id - *self.existing_footnotes
48+
);
49+
Event::Html(reference.into())
50+
}
51+
52+
fn collect_footnote_def(&mut self) -> Vec<Event<'a>> {
53+
let mut content = Vec::new();
54+
while let Some((event, _)) = self.inner.next() {
55+
match event {
56+
Event::End(TagEnd::FootnoteDefinition) => break,
57+
Event::FootnoteReference(ref reference) => {
58+
content.push(self.handle_footnote_reference(reference));
59+
}
60+
event => content.push(event),
61+
}
62+
}
63+
content
64+
}
3765
}
3866

3967
impl<'a, 'b, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, 'b, I> {
4068
type Item = SpannedEvent<'a>;
4169

4270
fn next(&mut self) -> Option<Self::Item> {
4371
loop {
44-
match self.inner.next() {
72+
let next = self.inner.next();
73+
match next {
4574
Some((Event::FootnoteReference(ref reference), range)) => {
46-
// When we see a reference (to a footnote we may not know) the definition of,
47-
// reserve a number for it, and emit a link to that number.
48-
let (_, id) = self.get_entry(reference);
49-
let reference = format!(
50-
"<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{1}</a></sup>",
51-
id,
52-
// Although the ID count is for the whole page, the footnote reference
53-
// are local to the item so we make this ID "local" when displayed.
54-
id - *self.existing_footnotes
55-
);
56-
return Some((Event::Html(reference.into()), range));
75+
return Some((self.handle_footnote_reference(reference), range));
5776
}
5877
Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
5978
// When we see a footnote definition, collect the assocated content, and store
6079
// that for rendering later.
61-
let content = collect_footnote_def(&mut self.inner);
80+
let content = self.collect_footnote_def();
6281
let (entry_content, _) = self.get_entry(&def);
6382
*entry_content = content;
6483
}
@@ -80,17 +99,6 @@ impl<'a, 'b, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, 'b
8099
}
81100
}
82101

83-
fn collect_footnote_def<'a>(events: impl Iterator<Item = SpannedEvent<'a>>) -> Vec<Event<'a>> {
84-
let mut content = Vec::new();
85-
for (event, _) in events {
86-
if let Event::End(TagEnd::FootnoteDefinition) = event {
87-
break;
88-
}
89-
content.push(event);
90-
}
91-
content
92-
}
93-
94102
fn render_footnotes_defs(mut footnotes: Vec<FootnoteDef<'_>>) -> String {
95103
let mut ret = String::from("<div class=\"footnotes\"><hr><ol>");
96104

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Checks that footnote references in footnote definitions are correctly generated.
2+
// Regression test for <https://github.com/rust-lang/rust/issues/131946>.
3+
4+
#![crate_name = "foo"]
5+
6+
//@ has 'foo/index.html'
7+
//@ has - '//*[@class="docblock"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1'
8+
//@ has - '//li[@id="fn1"]/p' 'meow'
9+
//@ has - '//li[@id="fn1"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2'
10+
//@ has - '//li[@id="fn1"]//a[@href="#fn2"]' '2'
11+
//@ has - '//li[@id="fn2"]/p' 'uwu'
12+
//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1'
13+
//@ has - '//li[@id="fn2"]//a[@href="#fn1"]' '1'
14+
15+
//! # footnote-hell
16+
//!
17+
//! Hello [^a].
18+
//!
19+
//! [^a]: meow [^b]
20+
//! [^b]: uwu [^a]

0 commit comments

Comments
 (0)