From 4547b622d8d29df964fa2914213088b148c498fc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:32 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- src/librustdoc/html/render/mod.rs | 265 +++++++++++++++++++++++--------------- 1 file changed, 158 insertions(+), 107 deletions(-) (limited to 'src/librustdoc/html/render/mod.rs') diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 96c57c8c8..36d15ec3b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -59,7 +59,7 @@ use rustc_span::{ symbol::{sym, Symbol}, BytePos, FileName, RealFileName, }; -use serde::ser::SerializeSeq; +use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Serialize, Serializer}; use crate::clean::{self, ItemId, RenderedLink, SelfTy}; @@ -70,8 +70,8 @@ use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ href, join_with_double_colon, print_abi_with_space, print_constness_with_space, - print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError, - PrintWithSpace, + print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space, + Buffer, Ending, HrefError, PrintWithSpace, }; use crate::html::highlight; use crate::html::markdown::{ @@ -747,11 +747,12 @@ fn assoc_const( extra: &str, cx: &Context<'_>, ) { + let tcx = cx.tcx(); write!( w, "{extra}{vis}const {name}: {ty}", extra = extra, - vis = it.visibility.print_with_space(it.item_id, cx), + vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), href = assoc_href_attr(it, link, cx), name = it.name.as_ref().unwrap(), ty = ty.print(cx), @@ -764,7 +765,7 @@ fn assoc_const( // This hurts readability in this context especially when more complex expressions // are involved and it doesn't add much of value. // Find a way to print constants here without all that jazz. - write!(w, "{}", Escape(&default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())))); + write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx)))); } } @@ -802,17 +803,18 @@ fn assoc_method( d: &clean::FnDecl, link: AssocItemLink<'_>, parent: ItemType, - cx: &Context<'_>, + cx: &mut Context<'_>, render_mode: RenderMode, ) { - let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item"); + let tcx = cx.tcx(); + let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); - let vis = meth.visibility.print_with_space(meth.item_id, cx).to_string(); + let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string(); // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. let constness = match render_mode { RenderMode::Normal => { - print_constness_with_space(&header.constness, meth.const_stability(cx.tcx())) + print_constness_with_space(&header.constness, meth.const_stability(tcx)) } RenderMode::ForDeref { .. } => "", }; @@ -834,6 +836,8 @@ fn assoc_method( + name.as_str().len() + generics_len; + let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx)); + let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; @@ -843,10 +847,10 @@ fn assoc_method( render_attributes_in_code(w, meth); (0, "", Ending::Newline) }; - w.reserve(header_len + "{".len() + "".len()); + w.reserve(header_len + "{".len() + "".len()); write!( w, - "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\ + "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\ {generics}{decl}{notable_traits}{where_clause}", indent = indent_str, vis = vis, @@ -859,9 +863,9 @@ fn assoc_method( name = name, generics = g.print(cx), decl = d.full_print(header_len, indent, cx), - notable_traits = notable_traits_decl(d, cx), + notable_traits = notable_traits.unwrap_or_default(), where_clause = print_where_clause(g, cx, indent, end_newline), - ) + ); } /// Writes a span containing the versions at which an item became stable and/or const-stable. For @@ -961,7 +965,7 @@ fn render_assoc_item( item: &clean::Item, link: AssocItemLink<'_>, parent: ItemType, - cx: &Context<'_>, + cx: &mut Context<'_>, render_mode: RenderMode, ) { match &*item.kind { @@ -1067,7 +1071,7 @@ fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) { w, "

\ {title}\ - \ + §\

" ); } @@ -1271,88 +1275,133 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { - let mut out = Buffer::html(); +pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option { + let mut has_notable_trait = false; + + let did = ty.def_id(cx.cache())?; - if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t))) + // Box has pass-through impls for Read, Write, Iterator, and Future when the + // boxed type implements one of those. We don't want to treat every Box return + // as being notably an Iterator (etc), though, so we exempt it. Pin has the same + // issue, with a pass-through impl for Future. + if Some(did) == cx.tcx().lang_items().owned_box() + || Some(did) == cx.tcx().lang_items().pin_type() { - // Box has pass-through impls for Read, Write, Iterator, and Future when the - // boxed type implements one of those. We don't want to treat every Box return - // as being notably an Iterator (etc), though, so we exempt it. Pin has the same - // issue, with a pass-through impl for Future. - if Some(did) == cx.tcx().lang_items().owned_box() - || Some(did) == cx.tcx().lang_items().pin_type() - { - return "".to_string(); - } - if let Some(impls) = cx.cache().impls.get(&did) { - for i in impls { - let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) + return None; + } + + if let Some(impls) = cx.cache().impls.get(&did) { + for i in impls { + let impl_ = i.inner_impl(); + if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + // Two different types might have the same did, + // without actually being the same. + continue; + } + if let Some(trait_) = &impl_.trait_ { + let trait_did = trait_.def_id(); + + if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) { - // Two different types might have the same did, - // without actually being the same. - continue; + has_notable_trait = true; } - if let Some(trait_) = &impl_.trait_ { - let trait_did = trait_.def_id(); - - if cx - .cache() - .traits - .get(&trait_did) - .map_or(false, |t| t.is_notable_trait(cx.tcx())) - { - if out.is_empty() { - write!( - &mut out, - "Notable traits for {}\ - ", - impl_.for_.print(cx) - ); - } + } + } + } - //use the "where" class here to make it small - write!( + if has_notable_trait { + cx.types_with_notable_traits.insert(ty.clone()); + Some(format!( + " ", + ty = Escape(&format!("{:#}", ty.print(cx))), + )) + } else { + None + } +} + +fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { + let mut out = Buffer::html(); + + let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this"); + + let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this"); + + for i in impls { + let impl_ = i.inner_impl(); + if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + // Two different types might have the same did, + // without actually being the same. + continue; + } + if let Some(trait_) = &impl_.trait_ { + let trait_did = trait_.def_id(); + + if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) { + if out.is_empty() { + write!( + &mut out, + "

Notable traits for {}

\ +
",
+                        impl_.for_.print(cx)
+                    );
+                }
+
+                //use the "where" class here to make it small
+                write!(
+                    &mut out,
+                    "{}",
+                    impl_.print(false, cx)
+                );
+                for it in &impl_.items {
+                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
+                        out.push_str("    ");
+                        let empty_set = FxHashSet::default();
+                        let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
+                        assoc_type(
                             &mut out,
-                            "{}",
-                            impl_.print(false, cx)
+                            it,
+                            &tydef.generics,
+                            &[], // intentionally leaving out bounds
+                            Some(&tydef.type_),
+                            src_link,
+                            0,
+                            cx,
                         );
-                        for it in &impl_.items {
-                            if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
-                                out.push_str("    ");
-                                let empty_set = FxHashSet::default();
-                                let src_link =
-                                    AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                                assoc_type(
-                                    &mut out,
-                                    it,
-                                    &tydef.generics,
-                                    &[], // intentionally leaving out bounds
-                                    Some(&tydef.type_),
-                                    src_link,
-                                    0,
-                                    cx,
-                                );
-                                out.push_str(";");
-                            }
-                        }
+                        out.push_str(";");
                     }
                 }
             }
         }
     }
-
-    if !out.is_empty() {
-        out.insert_str(
-            0,
-            "ⓘ\
-            ",
-        );
-        out.push_str("");
+    if out.is_empty() {
+        write!(&mut out, "
",); } - out.into_inner() + (format!("{:#}", ty.print(cx)), out.into_inner()) +} + +pub(crate) fn notable_traits_json<'a>( + tys: impl Iterator, + cx: &Context<'_>, +) -> String { + let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect(); + mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2)); + struct NotableTraitsMap(Vec<(String, String)>); + impl Serialize for NotableTraitsMap { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.0.len()))?; + for item in &self.0 { + map.serialize_entry(&item.0, &item.1)?; + } + map.end() + } + } + serde_json::to_string(&NotableTraitsMap(mp)) + .expect("serialize (string, string) -> json object cannot fail") } #[derive(Clone, Copy, Debug)] @@ -1487,7 +1536,7 @@ fn render_impl( render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); render_assoc_item( @@ -1513,7 +1562,7 @@ fn render_impl( render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); assoc_const( @@ -1538,7 +1587,7 @@ fn render_impl( write!(w, "
", id, item_type, in_trait_class); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); assoc_type( @@ -1564,7 +1613,7 @@ fn render_impl( ); if trait_.is_some() { // Anchors are only used on trait impls. - write!(w, "", id); + write!(w, "§", id); } w.write_str("

"); assoc_type( @@ -1797,7 +1846,7 @@ pub(crate) fn render_impl_summary( }; write!(w, "
", id, aliases); render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); - write!(w, "", id); + write!(w, "§", id); write!(w, "

"); if let Some(use_absolute) = use_absolute { @@ -2231,12 +2280,12 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea let fields = get_struct_fields_name(&s.fields); if !fields.is_empty() { - match s.struct_type { - CtorKind::Fictive => { + match s.ctor_kind { + None => { print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter()); } - CtorKind::Fn => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"), - CtorKind::Const => {} + Some(CtorKind::Fn) => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"), + Some(CtorKind::Const) => {} } } @@ -2866,11 +2915,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite ); if line_ranges.len() > 1 { - write!(w, r#" "#); - } - - if needs_expansion { - write!(w, r#""#); + write!(w, r#" "#); } // Look for the example file in the source map if it exists, otherwise return a dummy span @@ -2892,9 +2937,6 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite })() .unwrap_or(rustc_span::DUMMY_SP); - // The root path is the inverse of Context::current - let root_path = vec!["../"; cx.current.len() - 1].join(""); - let mut decoration_info = FxHashMap::default(); decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]); decoration_info.insert("highlight", byte_ranges); @@ -2904,9 +2946,9 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite contents_subset, file_span, cx, - &root_path, + &cx.root_path(), highlight::DecorationInfo(decoration_info), - sources::SourceContext::Embedded { offset: line_min }, + sources::SourceContext::Embedded { offset: line_min, needs_expansion }, ); write!(w, ""); @@ -2915,14 +2957,23 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // The call locations are output in sequence, so that sequence needs to be determined. // Ideally the most "relevant" examples would be shown first, but there's no general algorithm - // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to - // understand at a glance. + // for determining relevance. We instead proxy relevance with the following heuristics: + // 1. Code written to be an example is better than code not written to be an example, e.g. + // a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo + // directory structure in Rustdoc, so we proxy this by prioritizing code that comes from + // a --crate-type bin. + // 2. Smaller examples are better than large examples. So we prioritize snippets that have + // the smallest number of lines in their enclosing item. + // 3. Finally we sort by the displayed file name, which is arbitrary but prevents the + // ordering of examples from randomly changing between Rustdoc invocations. let ordered_locations = { - let sort_criterion = |(_, call_data): &(_, &CallData)| { + fn sort_criterion<'a>( + (_, call_data): &(&PathBuf, &'a CallData), + ) -> (bool, u32, &'a String) { // Use the first location because that's what the user will see initially let (lo, hi) = call_data.locations[0].enclosing_item.byte_span; - hi - lo - }; + (!call_data.is_bin, hi - lo, &call_data.display_name) + } let mut locs = call_locations.iter().collect::>(); locs.sort_by_key(sort_criterion); -- cgit v1.2.3