summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/render')
-rw-r--r--src/librustdoc/html/render/context.rs19
-rw-r--r--src/librustdoc/html/render/mod.rs77
-rw-r--r--src/librustdoc/html/render/print_item.rs269
-rw-r--r--src/librustdoc/html/render/search_index.rs40
-rw-r--r--src/librustdoc/html/render/type_layout.rs86
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())
+ })
+}