diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b141820fe42..aeaee524fd4 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -567,11 +567,12 @@ struct SummaryLine<'a, I: Iterator- >> {
inner: I,
started: bool,
depth: u32,
+ skipped_tags: u32,
}
impl<'a, I: Iterator
- >> SummaryLine<'a, I> {
fn new(iter: I) -> Self {
- SummaryLine { inner: iter, started: false, depth: 0 }
+ SummaryLine { inner: iter, started: false, depth: 0, skipped_tags: 0 }
}
}
@@ -601,6 +602,7 @@ impl<'a, I: Iterator
- >> Iterator for SummaryLine<'a, I> {
let is_allowed_tag = match event {
Event::Start(ref c) => {
if is_forbidden_tag(c) {
+ self.skipped_tags += 1;
return None;
}
self.depth += 1;
@@ -608,6 +610,7 @@ impl<'a, I: Iterator
- >> Iterator for SummaryLine<'a, I> {
}
Event::End(ref c) => {
if is_forbidden_tag(c) {
+ self.skipped_tags += 1;
return None;
}
self.depth -= 1;
@@ -616,6 +619,9 @@ impl<'a, I: Iterator
- >> Iterator for SummaryLine<'a, I> {
}
_ => true,
};
+ if !is_allowed_tag {
+ self.skipped_tags += 1;
+ }
return if !is_allowed_tag {
if is_start {
Some(Event::Start(Tag::Paragraph))
@@ -1096,11 +1102,11 @@ impl MarkdownItemInfo<'_> {
}
impl MarkdownSummaryLine<'_> {
- pub(crate) fn into_string(self) -> String {
+ pub(crate) fn into_string_with_has_more_content(self) -> (String, bool) {
let MarkdownSummaryLine(md, links) = self;
// This is actually common enough to special-case
if md.is_empty() {
- return String::new();
+ return (String::new(), false);
}
let mut replacer = |broken_link: BrokenLink<'_>| {
@@ -1110,17 +1116,26 @@ impl MarkdownSummaryLine<'_> {
.map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
- let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
+ let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer))
+ .peekable();
+ let mut summary = SummaryLine::new(p);
let mut s = String::new();
- let without_paragraphs = LinkReplacer::new(SummaryLine::new(p), links).filter(|event| {
+ let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| {
!matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
});
html::push_html(&mut s, without_paragraphs);
- s
+ let has_more_content =
+ matches!(summary.inner.peek(), Some(Event::Start(_))) || summary.skipped_tags > 0;
+
+ (s, has_more_content)
+ }
+
+ pub(crate) fn into_string(self) -> String {
+ self.into_string_with_has_more_content().0
}
}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 80fbe9c1f06..146e5010e4e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -467,9 +467,10 @@ fn document_short(
return;
}
if let Some(s) = item.doc_value() {
- let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
+ let (mut summary_html, has_more_content) =
+ MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
- if s.contains('\n') {
+ if has_more_content {
let link = format!(r#" Read more"#, assoc_href_attr(item, link, cx));
if let Some(idx) = summary_html.rfind("
") {
diff --git a/src/test/rustdoc/read-more-unneeded.rs b/src/test/rustdoc/read-more-unneeded.rs
new file mode 100644
index 00000000000..0303e444261
--- /dev/null
+++ b/src/test/rustdoc/read-more-unneeded.rs
@@ -0,0 +1,34 @@
+// Regression test for https://github.com/rust-lang/rust/issues/105677.
+// This test ensures that the "Read more" link is only generated when
+// there is actually more documentation to read after the short summary.
+
+#![crate_name = "foo"]
+
+pub trait MyFrom {
+ /// # Hello
+ /// ## Yolo
+ /// more!
+ fn try_from1();
+ /// a
+ /// b
+ /// c
+ fn try_from2();
+ /// a
+ ///
+ /// b
+ ///
+ /// c
+ fn try_from3();
+}
+
+pub struct NonZero;
+
+// @has 'foo/struct.NonZero.html'
+impl MyFrom for NonZero {
+ // @matches - '//*[@class="docblock"]' '^Hello Read more$'
+ fn try_from1() {}
+ // @matches - '//*[@class="docblock"]' '^a\sb\sc$'
+ fn try_from2() {}
+ // @matches - '//*[@class="docblock"]' '^a Read more$'
+ fn try_from3() {}
+}
diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs
index 195cdf009b9..9cf3226f738 100644
--- a/src/test/rustdoc/trait-impl.rs
+++ b/src/test/rustdoc/trait-impl.rs
@@ -30,8 +30,6 @@ impl Trait for Struct {
// @has - '//*[@id="method.b"]/../../div[@class="docblock"]' 'These docs contain'
// @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a' 'reference link'
// @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a/@href' 'https://example.com'
- // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a' 'Read more'
- // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.b'
fn b() {}
// @!has - '//*[@id="method.c"]/../../div[@class="docblock"]' 'code block'