diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /src/librustdoc/html/render | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/librustdoc/html/render')
-rw-r--r-- | src/librustdoc/html/render/context.rs | 19 | ||||
-rw-r--r-- | src/librustdoc/html/render/mod.rs | 77 | ||||
-rw-r--r-- | src/librustdoc/html/render/print_item.rs | 269 | ||||
-rw-r--r-- | src/librustdoc/html/render/search_index.rs | 40 | ||||
-rw-r--r-- | src/librustdoc/html/render/type_layout.rs | 86 |
5 files changed, 245 insertions, 246 deletions
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index ac5054ce1..56af257fd 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -122,9 +122,9 @@ pub(crate) struct SharedContext<'tcx> { /// the crate. redirections: Option<RefCell<FxHashMap<String, String>>>, - /// Correspondance map used to link types used in the source code pages to allow to click on + /// Correspondence map used to link types used in the source code pages to allow to click on /// links to jump to the type's definition. - pub(crate) span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>, + pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>, /// The [`Cache`] used during rendering. pub(crate) cache: Cache, @@ -184,11 +184,8 @@ impl<'tcx> Context<'tcx> { }; title.push_str(" - Rust"); let tyname = it.type_(); - let desc = it - .doc_value() - .as_ref() - .map(|doc| plain_text_summary(doc, &it.link_names(&self.cache()))); - let desc = if let Some(desc) = desc { + let desc = plain_text_summary(&it.doc_value(), &it.link_names(&self.cache())); + let desc = if !desc.is_empty() { desc } else if it.is_crate() { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) @@ -531,7 +528,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { errors: receiver, redirections: if generate_redirect_map { Some(Default::default()) } else { None }, show_type_layout, - span_correspondance_map: matches, + span_correspondence_map: matches, cache, call_locations, }; @@ -647,7 +644,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { </div>\ <noscript>\ <section>\ - You need to enable Javascript be able to update your settings.\ + You need to enable JavaScript be able to update your settings.\ </section>\ </noscript>\ <link rel=\"stylesheet\" \ @@ -709,7 +706,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { </div>\ <noscript>\ <section>\ - <p>You need to enable Javascript to use keyboard commands or search.</p>\ + <p>You need to enable JavaScript to use keyboard commands or search.</p>\ <p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\ </section>\ </noscript>", @@ -746,7 +743,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Flush pending errors. Rc::get_mut(&mut self.shared).unwrap().fs.close(); let nb_errors = - self.shared.errors.iter().map(|err| self.tcx().sess.struct_err(&err).emit()).count(); + self.shared.errors.iter().map(|err| self.tcx().sess.struct_err(err).emit()).count(); if nb_errors > 0 { Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), "")) } else { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 463184aca..9e3b5d10a 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -32,6 +32,7 @@ mod context; mod print_item; mod sidebar; mod span_map; +mod type_layout; mod write_shared; pub(crate) use self::context::*; @@ -47,7 +48,6 @@ use std::str; use std::string::ToString; use askama::Template; -use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -468,7 +468,8 @@ fn document_short<'a, 'cx: 'a>( if !show_def_docs { return Ok(()); } - if let Some(s) = item.doc_value() { + let s = item.doc_value(); + if !s.is_empty() { let (mut summary_html, has_more_content) = MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content(); @@ -511,7 +512,7 @@ fn document_full_inner<'a, 'cx: 'a>( heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(move |f| { - if let Some(s) = item.collapsed_doc_value() { + if let Some(s) = item.opt_doc_value() { debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { write!( @@ -848,10 +849,10 @@ fn assoc_method( let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; - write!(w, "{}", render_attributes_in_pre(meth, indent_str)); + write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx)); (4, indent_str, Ending::NoNewline) } else { - render_attributes_in_code(w, meth); + render_attributes_in_code(w, meth, tcx); (0, "", Ending::Newline) }; w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len()); @@ -1020,36 +1021,15 @@ fn render_assoc_item( } } -const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive]; - -fn attributes(it: &clean::Item) -> Vec<String> { - it.attrs - .other_attrs - .iter() - .filter_map(|attr| { - if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { - Some( - pprust::attribute_to_string(attr) - .replace("\\\n", "") - .replace('\n', "") - .replace(" ", " "), - ) - } else { - None - } - }) - .collect() -} - // When an attribute is rendered inside a `<pre>` tag, it is formatted using // a whitespace prefix and newline. -fn render_attributes_in_pre<'a>( +fn render_attributes_in_pre<'a, 'b: 'a>( it: &'a clean::Item, prefix: &'a str, -) -> impl fmt::Display + Captures<'a> { + tcx: TyCtxt<'b>, +) -> impl fmt::Display + Captures<'a> + Captures<'b> { crate::html::format::display_fn(move |f| { - for a in attributes(it) { + for a in it.attributes(tcx, false) { writeln!(f, "{}{}", prefix, a)?; } Ok(()) @@ -1058,8 +1038,8 @@ fn render_attributes_in_pre<'a>( // When an attribute is rendered inside a <code> tag, it is formatted using // a div to produce a newline after it. -fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) { - for a in attributes(it) { +fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) { + for a in it.attributes(tcx, false) { write!(w, "<div class=\"code-attribute\">{}</div>", a); } } @@ -1154,10 +1134,10 @@ fn render_assoc_items_inner( let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); - let (render_mode, id) = match what { + let (render_mode, id, class_html) = match what { AssocItemRender::All => { write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations"); - (RenderMode::Normal, "implementations-list".to_owned()) + (RenderMode::Normal, "implementations-list".to_owned(), "") } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { let id = @@ -1174,7 +1154,11 @@ fn render_assoc_items_inner( ), &id, ); - (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id)) + ( + RenderMode::ForDeref { mut_: deref_mut_ }, + cx.derive_id(id), + r#" class="impl-items""#, + ) } }; let mut impls_buf = Buffer::html(); @@ -1198,7 +1182,7 @@ fn render_assoc_items_inner( } if !impls_buf.is_empty() { write!(w, "{}", tmp_buf.into_inner()).unwrap(); - write!(w, "<div id=\"{}\">", id).unwrap(); + write!(w, "<div id=\"{id}\"{class_html}>").unwrap(); write!(w, "{}", impls_buf.into_inner()).unwrap(); w.write_str("</div>").unwrap(); } @@ -1493,7 +1477,7 @@ fn render_impl( if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - if item.doc_value().is_some() { + if !item.doc_value().is_empty() { document_item_info(cx, it, Some(parent)) .render_into(&mut info_buffer) .unwrap(); @@ -1764,11 +1748,11 @@ fn render_impl( write!(w, "</summary>") } - if let Some(ref dox) = i.impl_item.collapsed_doc_value() { + if let Some(ref dox) = i.impl_item.opt_doc_value() { if trait_.is_none() && i.inner_impl().items.is_empty() { w.write_str( "<div class=\"item-info\">\ - <div class=\"stab empty-impl\">This impl block contains no items.</div> + <div class=\"stab empty-impl\">This impl block contains no items.</div>\ </div>", ); } @@ -1787,12 +1771,14 @@ fn render_impl( .into_string() ); } + if !default_impl_items.is_empty() || !impl_items.is_empty() { + w.write_str("<div class=\"impl-items\">"); + close_tags.insert_str(0, "</div>"); + } } if !default_impl_items.is_empty() || !impl_items.is_empty() { - w.write_str("<div class=\"impl-items\">"); w.push_buffer(default_impl_items); w.push_buffer(impl_items); - close_tags.insert_str(0, "</div>"); } w.write_str(&close_tags); } @@ -1947,8 +1933,6 @@ pub(crate) fn small_url_encode(s: String) -> String { // While the same is not true for hashes, rustdoc only needs to be // consistent with itself when encoding them. st += "+"; - } else if b == b'%' { - st += "%%"; } else { write!(st, "%{:02X}", b).unwrap(); } @@ -2217,7 +2201,9 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> { } clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => { work.push_back(self_type); - process_path(trait_.def_id()); + if let Some(trait_) = trait_ { + process_path(trait_.def_id()); + } } _ => {} } @@ -2271,8 +2257,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c Ok(contents) => contents, Err(err) => { let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner()); - tcx.sess - .span_err(span, &format!("failed to read file {}: {}", path.display(), err)); + tcx.sess.span_err(span, format!("failed to read file {}: {}", path.display(), err)); return false; } }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 9a968e48b..62027a3fa 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -6,16 +6,16 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_middle::middle::stability; -use rustc_middle::span_bug; -use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self, Adt, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_target::abi::{LayoutS, Primitive, TagEncoding, Variants}; +use std::borrow::Borrow; +use std::cell::{RefCell, RefMut}; use std::cmp::Ordering; use std::fmt; use std::rc::Rc; +use super::type_layout::document_type_layout; use super::{ collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference, item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, @@ -218,6 +218,53 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("</details>").unwrap(); } +trait ItemTemplate<'a, 'cx: 'a>: askama::Template + fmt::Display { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>); +} + +fn item_template_document<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, mut cx) = templ.item_and_mut_cx(); + let v = document(*cx, item, None, HeadingOffset::H2); + write!(f, "{v}") + }) +} + +fn item_template_document_type_layout<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, cx) = templ.item_and_mut_cx(); + let def_id = item.item_id.expect_def_id(); + let v = document_type_layout(*cx, def_id); + write!(f, "{v}") + }) +} + +fn item_template_render_attributes_in_pre<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, cx) = templ.item_and_mut_cx(); + let tcx = cx.tcx(); + let v = render_attributes_in_pre(item, "", tcx); + write!(f, "{v}") + }) +} + +fn item_template_render_assoc_items<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, mut cx) = templ.item_and_mut_cx(); + let def_id = item.item_id.expect_def_id(); + let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All); + write!(f, "{v}") + }) +} + fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { write!(w, "{}", document(cx, item, None, HeadingOffset::H2)); @@ -358,18 +405,18 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: clean::ImportItem(ref import) => { let stab_tags = if let Some(import_def_id) = import.source.did { - let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id); + let ast_attrs = tcx.get_attrs_unchecked(import_def_id); let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs)); // Just need an item with the correct def_id and attrs let import_item = clean::Item { item_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), + cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg), ..myitem.clone() }; - let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string()); + let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); stab_tags } else { None @@ -407,8 +454,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let unsafety_flag = match *myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(_) - if myitem.fn_header(cx.tcx()).unwrap().unsafety - == hir::Unsafety::Unsafe => + if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe => { "<sup title=\"unsafe function\">⚠</sup>" } @@ -422,9 +468,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: _ => "", }; - let doc_value = myitem.doc_value().unwrap_or_default(); w.write_str(ITEM_TABLE_ROW_OPEN); - let docs = MarkdownSummaryLine(&doc_value, &myitem.links(cx)).into_string(); + let docs = + MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); let (docs_before, docs_after) = if docs.is_empty() { ("", "") } else { @@ -441,7 +487,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: {docs_before}{docs}{docs_after}", name = myitem.name.unwrap(), visibility_emoji = visibility_emoji, - stab_tags = extra_info_tags(myitem, item, cx.tcx()), + stab_tags = extra_info_tags(myitem, item, tcx), class = myitem.type_(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), @@ -550,7 +596,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle w, "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", - attrs = render_attributes_in_pre(it, ""), + attrs = render_attributes_in_pre(it, "", tcx), vis = visibility, constness = constness, asyncness = asyncness, @@ -591,7 +637,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: it.name.unwrap(), t.generics.print(cx), bounds, - attrs = render_attributes_in_pre(it, ""), + attrs = render_attributes_in_pre(it, "", tcx), ); if !t.generics.where_predicates.is_empty() { @@ -888,7 +934,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { - let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx()); + let provided_methods = implementor.inner_impl().provided_trait_methods(tcx); let assoc_link = AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods); render_impl( @@ -921,7 +967,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } w.write_str("</div>"); - if t.is_auto(cx.tcx()) { + if t.is_auto(tcx) { write_small_section_header( w, "synthetic-implementors", @@ -950,7 +996,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: "<div id=\"implementors-list\"></div>", ); - if t.is_auto(cx.tcx()) { + if t.is_auto(tcx) { write_small_section_header( w, "synthetic-implementors", @@ -1065,7 +1111,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: & t.generics.print(cx), print_where_clause(&t.generics, cx, 0, Ending::Newline), bounds(&t.bounds, true, cx), - attrs = render_attributes_in_pre(it, ""), + attrs = render_attributes_in_pre(it, "", cx.tcx()), ); }); @@ -1087,7 +1133,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), bounds = bounds(&t.bounds, false, cx), - attrs = render_attributes_in_pre(it, ""), + attrs = render_attributes_in_pre(it, "", cx.tcx()), ); }); @@ -1111,7 +1157,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), type_ = t.type_.print(cx), - attrs = render_attributes_in_pre(it, ""), + attrs = render_attributes_in_pre(it, "", cx.tcx()), ); }); } @@ -1133,32 +1179,18 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: #[derive(Template)] #[template(path = "item_union.html")] struct ItemUnion<'a, 'cx> { - cx: std::cell::RefCell<&'a mut Context<'cx>>, + cx: RefCell<&'a mut Context<'cx>>, it: &'a clean::Item, s: &'a clean::Union, } - impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { - fn render_assoc_items<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let def_id = self.it.item_id.expect_def_id(); - let mut cx = self.cx.borrow_mut(); - let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All); - write!(f, "{v}") - }) - } - fn document_type_layout<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let def_id = self.it.item_id.expect_def_id(); - let cx = self.cx.borrow_mut(); - let v = document_type_layout(*cx, def_id); - write!(f, "{v}") - }) + impl<'a, 'cx: 'a> ItemTemplate<'a, 'cx> for ItemUnion<'a, 'cx> { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>) { + (self.it, self.cx.borrow_mut()) } + } + + impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { let cx = self.cx.borrow_mut(); @@ -1166,21 +1198,6 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: write!(f, "{v}") }) } - fn render_attributes_in_pre<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let v = render_attributes_in_pre(self.it, ""); - write!(f, "{v}") - }) - } - fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let mut cx = self.cx.borrow_mut(); - let v = document(*cx, self.it, None, HeadingOffset::H2); - write!(f, "{v}") - }) - } fn document_field<'b>( &'b self, field: &'a clean::Item, @@ -1220,7 +1237,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: } } - ItemUnion { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap(); + ItemUnion { cx: RefCell::new(cx), it, s }.render_into(w).unwrap(); } fn print_tuple_struct_fields<'a, 'cx: 'a>( @@ -1246,13 +1263,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let tcx = cx.tcx(); let count_variants = e.variants().count(); wrap_item(w, |mut w| { + render_attributes_in_code(w, it, tcx); write!( w, - "{attrs}{}enum {}{}", + "{}enum {}{}", visibility_print_with_space(it.visibility(tcx), it.item_id, cx), it.name.unwrap(), e.generics.print(cx), - attrs = render_attributes_in_pre(it, ""), ); if !print_where_clause_and_check(w, &e.generics, cx) { // If there wasn't a `where` clause, we add a whitespace. @@ -1339,7 +1356,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: clean::VariantKind::Tuple(fields) => { // Documentation on tuple variant fields is rare, so to reduce noise we only emit // the section if at least one field is documented. - if fields.iter().any(|f| f.doc_value().is_some()) { + if fields.iter().any(|f| !f.doc_value().is_empty()) { Some(("Tuple Fields", fields)) } else { None @@ -1447,7 +1464,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_item(w, |w| { let tcx = cx.tcx(); - render_attributes_in_code(w, it); + render_attributes_in_code(w, it, tcx); write!( w, @@ -1494,7 +1511,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_item(w, |w| { - render_attributes_in_code(w, it); + render_attributes_in_code(w, it, cx.tcx()); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); }); @@ -1542,11 +1559,12 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document_type_layout(cx, def_id)); } -fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { - wrap_item(w, |w| { - render_attributes_in_code(w, it); +fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { + render_attributes_in_code(buffer, it, cx.tcx()); write!( - w, + buffer, "{vis}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), mutability = s.mutability.print_with_space(), @@ -1554,13 +1572,16 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean typ = s.type_.print(cx) ); }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + + write!(w, "{}", buffer.into_inner()).unwrap(); + + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); } fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { wrap_item(w, |w| { w.write_str("extern {\n"); - render_attributes_in_code(w, it); + render_attributes_in_code(w, it, cx.tcx()); write!( w, " {}type {};\n}}", @@ -1933,118 +1954,6 @@ fn document_non_exhaustive<'a>(item: &'a clean::Item) -> impl fmt::Display + 'a }) } -fn document_type_layout<'a, 'cx: 'a>( - cx: &'a Context<'cx>, - ty_def_id: DefId, -) -> impl fmt::Display + 'a + Captures<'cx> { - fn write_size_of_layout(mut w: impl fmt::Write, layout: &LayoutS, tag_size: u64) { - if layout.abi.is_unsized() { - write!(w, "(unsized)").unwrap(); - } else { - let size = layout.size.bytes() - tag_size; - write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" }).unwrap(); - if layout.abi.is_uninhabited() { - write!( - w, - " (<a href=\"https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\">uninhabited</a>)" - ).unwrap(); - } - } - } - - display_fn(move |mut f| { - if !cx.shared.show_type_layout { - return Ok(()); - } - - writeln!( - f, - "<h2 id=\"layout\" class=\"small-section-header\"> \ - Layout<a href=\"#layout\" class=\"anchor\">§</a></h2>" - )?; - writeln!(f, "<div class=\"docblock\">")?; - - let tcx = cx.tcx(); - let param_env = tcx.param_env(ty_def_id); - let ty = tcx.type_of(ty_def_id).subst_identity(); - match tcx.layout_of(param_env.and(ty)) { - Ok(ty_layout) => { - writeln!( - f, - "<div class=\"warning\"><p><strong>Note:</strong> Most layout information is \ - <strong>completely unstable</strong> and may even differ between compilations. \ - The only exception is types with certain <code>repr(...)</code> attributes. \ - Please see the Rust Reference’s \ - <a href=\"https://doc.rust-lang.org/reference/type-layout.html\">“Type Layout”</a> \ - chapter for details on type layout guarantees.</p></div>" - )?; - f.write_str("<p><strong>Size:</strong> ")?; - write_size_of_layout(&mut f, &ty_layout.layout.0, 0); - writeln!(f, "</p>")?; - if let Variants::Multiple { variants, tag, tag_encoding, .. } = - &ty_layout.layout.variants() - { - if !variants.is_empty() { - f.write_str( - "<p><strong>Size for each variant:</strong></p>\ - <ul>", - )?; - - let Adt(adt, _) = ty_layout.ty.kind() else { - span_bug!(tcx.def_span(ty_def_id), "not an adt") - }; - - let tag_size = if let TagEncoding::Niche { .. } = tag_encoding { - 0 - } else if let Primitive::Int(i, _) = tag.primitive() { - i.size().bytes() - } else { - span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") - }; - - for (index, layout) in variants.iter_enumerated() { - let name = adt.variant(index).name; - write!(&mut f, "<li><code>{name}</code>: ")?; - write_size_of_layout(&mut f, layout, tag_size); - writeln!(&mut f, "</li>")?; - } - f.write_str("</ul>")?; - } - } - } - // This kind of layout error can occur with valid code, e.g. if you try to - // get the layout of a generic type such as `Vec<T>`. - Err(LayoutError::Unknown(_)) => { - writeln!( - f, - "<p><strong>Note:</strong> Unable to compute type layout, \ - possibly due to this type having generic parameters. \ - Layout can only be computed for concrete, fully-instantiated types.</p>" - )?; - } - // This kind of error probably can't happen with valid code, but we don't - // want to panic and prevent the docs from building, so we just let the - // user know that we couldn't compute the layout. - Err(LayoutError::SizeOverflow(_)) => { - writeln!( - f, - "<p><strong>Note:</strong> Encountered an error during type layout; \ - the type was too big.</p>" - )?; - } - Err(LayoutError::NormalizationFailure(_, _)) => { - writeln!( - f, - "<p><strong>Note:</strong> Encountered an error during type layout; \ - the type failed to be normalized.</p>" - )?; - } - } - - writeln!(f, "</div>") - }) -} - fn pluralize(count: usize) -> &'static str { if count > 1 { "s" } else { "" } } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index f5b4a3f5a..846299f02 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -28,9 +28,7 @@ pub(crate) fn build_index<'tcx>( // has since been learned. for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items { if let Some((fqp, _)) = cache.paths.get(&parent) { - let desc = item - .doc_value() - .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache))); + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); cache.search_index.push(IndexItem { ty: item.type_(), name: item.name.unwrap(), @@ -45,10 +43,8 @@ pub(crate) fn build_index<'tcx>( } } - let crate_doc = krate - .module - .doc_value() - .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(cache))); + let crate_doc = + short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache)); // Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, // we need the alias element to have an array of items. @@ -391,12 +387,14 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> { clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => { get_index_type_id(type_) } + // The type parameters are converted to generics in `add_generics_and_bounds_as_types` + clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), + clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), + // Not supported yet clean::BareFunction(_) | clean::Generic(_) | clean::ImplTrait(_) | clean::Tuple(_) - | clean::Slice(_) - | clean::Array(_, _) | clean::QPath { .. } | clean::Infer => None, } @@ -563,6 +561,30 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( } } insert_ty(res, arg.clone(), ty_generics); + } else if let Type::Slice(ref ty) = *arg { + let mut ty_generics = Vec::new(); + add_generics_and_bounds_as_types( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + cache, + ); + insert_ty(res, arg.clone(), ty_generics); + } else if let Type::Array(ref ty, _) = *arg { + let mut ty_generics = Vec::new(); + add_generics_and_bounds_as_types( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + cache, + ); + insert_ty(res, arg.clone(), ty_generics); } else { // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't. diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs new file mode 100644 index 000000000..c9b95b1e6 --- /dev/null +++ b/src/librustdoc/html/render/type_layout.rs @@ -0,0 +1,86 @@ +use askama::Template; + +use rustc_data_structures::captures::Captures; +use rustc_hir::def_id::DefId; +use rustc_middle::span_bug; +use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::Adt; +use rustc_span::symbol::Symbol; +use rustc_target::abi::{Primitive, TagEncoding, Variants}; + +use std::fmt; + +use crate::html::format::display_fn; +use crate::html::render::Context; + +#[derive(Template)] +#[template(path = "type_layout.html")] +struct TypeLayout<'cx> { + variants: Vec<(Symbol, TypeLayoutSize)>, + type_layout_size: Result<TypeLayoutSize, LayoutError<'cx>>, +} + +#[derive(Template)] +#[template(path = "type_layout_size.html")] +struct TypeLayoutSize { + is_unsized: bool, + is_uninhabited: bool, + size: u64, +} + +pub(crate) fn document_type_layout<'a, 'cx: 'a>( + cx: &'a Context<'cx>, + ty_def_id: DefId, +) -> impl fmt::Display + 'a + Captures<'cx> { + display_fn(move |f| { + if !cx.shared.show_type_layout { + return Ok(()); + } + + let tcx = cx.tcx(); + let param_env = tcx.param_env(ty_def_id); + let ty = tcx.type_of(ty_def_id).subst_identity(); + let type_layout = tcx.layout_of(param_env.and(ty)); + + let variants = + if let Ok(type_layout) = type_layout && + let Variants::Multiple { variants, tag, tag_encoding, .. } = + type_layout.layout.variants() && + !variants.is_empty() + { + let tag_size = + if let TagEncoding::Niche { .. } = tag_encoding { + 0 + } else if let Primitive::Int(i, _) = tag.primitive() { + i.size().bytes() + } else { + span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") + }; + variants + .iter_enumerated() + .map(|(variant_idx, variant_layout)| { + let Adt(adt, _) = type_layout.ty.kind() else { + span_bug!(tcx.def_span(ty_def_id), "not an adt") + }; + let name = adt.variant(variant_idx).name; + let is_unsized = variant_layout.abi.is_unsized(); + let is_uninhabited = variant_layout.abi.is_uninhabited(); + let size = variant_layout.size.bytes() - tag_size; + let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size }; + (name, type_layout_size) + }) + .collect() + } else { + Vec::new() + }; + + let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| { + let is_unsized = layout.abi.is_unsized(); + let is_uninhabited = layout.abi.is_uninhabited(); + let size = layout.size.bytes(); + TypeLayoutSize { is_unsized, is_uninhabited, size } + }); + + Ok(TypeLayout { variants, type_layout_size }.render_into(f).unwrap()) + }) +} |