diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e39652c6dd5..45412f55c15 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -82,6 +82,10 @@ impl Buffer { self.buffer.push_str(s); } + crate fn push_buffer(&mut self, other: Buffer) { + self.buffer.push_str(&other.buffer); + } + // Intended for consumption by write! and writeln! (std::fmt) but without // the fmt::Result return type imposed by fmt::Write (and avoiding the trait // import). diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 19b8dd15ad0..518dbc6eeb3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1281,99 +1281,6 @@ fn render_impl( let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); let mut close_tags = String::new(); - if render_mode == RenderMode::Normal { - let id = cx.derive_id(match i.inner_impl().trait_ { - Some(ref t) => { - if is_on_foreign_type { - get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx) - } else { - format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx)))) - } - } - None => "impl".to_string(), - }); - let aliases = if aliases.is_empty() { - String::new() - } else { - format!(" aliases=\"{}\"", aliases.join(",")) - }; - if let Some(use_absolute) = use_absolute { - write!( - w, - "
\ - \ -

\ - ", - id, aliases - ); - close_tags.insert_str(0, "

"); - write!(w, "{}", i.inner_impl().print(use_absolute, cx)); - if show_def_docs { - for it in &i.inner_impl().items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { - w.write_str(" "); - assoc_type( - w, - it, - &[], - Some(&tydef.type_), - AssocItemLink::Anchor(None), - "", - cx, - ); - w.write_str(";"); - } - } - } - w.write_str(""); - } else { - write!( - w, - "
\ - \ -

\ - {}", - id, - aliases, - i.inner_impl().print(false, cx) - ); - close_tags.insert_str(0, "

"); - } - write!(w, "", id); - render_stability_since_raw( - w, - i.impl_item.stable_since(tcx).as_deref(), - i.impl_item.const_stable_since(tcx).as_deref(), - outer_version, - outer_const_version, - ); - write_srclink(cx, &i.impl_item, w); - w.write_str(""); - - if trait_.is_some() { - if let Some(portability) = portability(&i.impl_item, Some(parent)) { - write!(w, "
{}
", portability); - } - } - - if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { - let mut ids = cx.id_map.borrow_mut(); - write!( - w, - "
{}
", - Markdown( - &*dox, - &i.impl_item.links(cx), - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) - .into_string() - ); - } - } - fn doc_impl_item( w: &mut Buffer, cx: &Context<'_>, @@ -1549,11 +1456,10 @@ fn render_impl( } } - w.write_str("
"); - close_tags.insert_str(0, "
"); + let mut impl_items = Buffer::empty_from(w); for trait_item in &i.inner_impl().items { doc_impl_item( - w, + &mut impl_items, cx, trait_item, if trait_.is_some() { &i.impl_item } else { parent }, @@ -1609,7 +1515,7 @@ fn render_impl( if show_default_items { if let Some(t) = trait_ { render_default_items( - w, + &mut impl_items, cx, &t.trait_, &i.inner_impl(), @@ -1621,6 +1527,111 @@ fn render_impl( ); } } + let details_str = if impl_items.is_empty() { + "" + } else { + "
" + }; + if render_mode == RenderMode::Normal { + let id = cx.derive_id(match i.inner_impl().trait_ { + Some(ref t) => { + if is_on_foreign_type { + get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx) + } else { + format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx)))) + } + } + None => "impl".to_string(), + }); + let aliases = if aliases.is_empty() { + String::new() + } else { + format!(" aliases=\"{}\"", aliases.join(",")) + }; + if let Some(use_absolute) = use_absolute { + write!( + w, + "{}

", + details_str, id, aliases + ); + if !impl_items.is_empty() { + close_tags.insert_str(0, "

"); + } + write!(w, "{}", i.inner_impl().print(use_absolute, cx)); + if show_def_docs { + for it in &i.inner_impl().items { + if let clean::TypedefItem(ref tydef, _) = *it.kind { + w.write_str(" "); + assoc_type( + w, + it, + &[], + Some(&tydef.type_), + AssocItemLink::Anchor(None), + "", + cx, + ); + w.write_str(";"); + } + } + } + w.write_str(""); + } else { + write!( + w, + "{}

{}", + details_str, + id, + aliases, + i.inner_impl().print(false, cx) + ); + if !impl_items.is_empty() { + close_tags.insert_str(0, ""); + } + } + write!(w, "", id); + render_stability_since_raw( + w, + i.impl_item.stable_since(tcx).as_deref(), + i.impl_item.const_stable_since(tcx).as_deref(), + outer_version, + outer_const_version, + ); + write_srclink(cx, &i.impl_item, w); + if impl_items.is_empty() { + w.write_str("

"); + } else { + w.write_str(""); + } + + if trait_.is_some() { + if let Some(portability) = portability(&i.impl_item, Some(parent)) { + write!(w, "
{}
", portability); + } + } + + if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { + let mut ids = cx.id_map.borrow_mut(); + write!( + w, + "
{}
", + Markdown( + &*dox, + &i.impl_item.links(cx), + &mut ids, + cx.shared.codes, + cx.shared.edition(), + &cx.shared.playground + ) + .into_string() + ); + } + } + if !impl_items.is_empty() { + w.write_str("
"); + w.push_buffer(impl_items); + close_tags.insert_str(0, "
"); + } w.write_str(&close_tags); } diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs new file mode 100644 index 00000000000..86dec32e625 --- /dev/null +++ b/src/test/rustdoc/empty-impls.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo' +pub struct Foo; + +pub trait EmptyTrait {} + +// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo' +impl EmptyTrait for Foo {} + +pub trait NotEmpty { + fn foo(&self); +} + +// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo' +impl NotEmpty for Foo { + fn foo(&self) {} +} diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs index daebe059f8e..ddc14e68675 100644 --- a/src/test/rustdoc/issue-53812.rs +++ b/src/test/rustdoc/issue-53812.rs @@ -12,9 +12,9 @@ macro_rules! array_impls { } } -// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/details[1]/summary/h3' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]/details[2]/summary/h3' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]/details[3]/summary/h3' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]/details[4]/summary/h3' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]/details[5]/summary/h3' 'MyStruct<[T; 10]>' +// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 }