Skip to content

Commit

Permalink
Rollup merge of #104129 - notriddle:notriddle/102576-js-notable-trait…
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth authored Nov 11, 2022
2 parents 55f07c7 + 53e8b49 commit 206928c
Show file tree
Hide file tree
Showing 16 changed files with 360 additions and 110 deletions.
4 changes: 0 additions & 4 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ impl Buffer {
self.buffer
}

pub(crate) fn insert_str(&mut self, idx: usize, s: &str) {
self.buffer.insert_str(idx, s);
}

pub(crate) fn push_str(&mut self, s: &str) {
self.buffer.push_str(s);
}
Expand Down
7 changes: 6 additions & 1 deletion src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ pub(crate) struct Context<'tcx> {
/// the source files are present in the html rendering, then this will be
/// `true`.
pub(crate) include_sources: bool,
/// Collection of all types with notable traits referenced in the current module.
pub(crate) types_with_notable_traits: FxHashSet<clean::Type>,
}

// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
#[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Context<'_>, 128);
rustc_data_structures::static_assert_size!(Context<'_>, 160);

/// Shared mutable state used in [`Context`] and elsewhere.
pub(crate) struct SharedContext<'tcx> {
Expand Down Expand Up @@ -532,6 +534,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
deref_id_map: FxHashMap::default(),
shared: Rc::new(scx),
include_sources,
types_with_notable_traits: FxHashSet::default(),
};

if emit_crate {
Expand Down Expand Up @@ -560,6 +563,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
id_map: IdMap::new(),
shared: Rc::clone(&self.shared),
include_sources: self.include_sources,
types_with_notable_traits: FxHashSet::default(),
}
}

Expand Down Expand Up @@ -803,6 +807,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
}
}
}

Ok(())
}

Expand Down
195 changes: 122 additions & 73 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -803,7 +803,7 @@ fn assoc_method(
d: &clean::FnDecl,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
cx: &mut Context<'_>,
render_mode: RenderMode,
) {
let tcx = cx.tcx();
Expand Down Expand Up @@ -836,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 = " ";
Expand All @@ -861,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
Expand Down Expand Up @@ -963,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 {
Expand Down Expand Up @@ -1273,88 +1275,135 @@ 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<String> {
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 has_notable_trait {
cx.types_with_notable_traits.insert(ty.clone());
Some(format!(
"<span class=\"notable-traits\" data-ty=\"{ty:#}\">\
<span class=\"notable-traits-tooltip\">ⓘ</span>\
</span>",
ty = 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,
"<h3 class=\"notable\">Notable traits for <code>{}</code></h3>\
<pre class=\"content\"><code>",
impl_.for_.print(cx)
);
}
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,
"<span class=\"notable\">Notable traits for {}</span>\
<code class=\"content\">",
impl_.for_.print(cx)
);
}

//use the "where" class here to make it small
write!(
//use the "where" class here to make it small
write!(
&mut out,
"<span class=\"where fmt-newline\">{}</span>",
impl_.print(false, cx)
);
for it in &impl_.items {
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
let empty_set = FxHashSet::default();
let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
assoc_type(
&mut out,
"<span class=\"where fmt-newline\">{}</span>",
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("<span class=\"where fmt-newline\"> ");
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(";</span>");
}
}
out.push_str(";</span>");
}
}
}
}
}

if !out.is_empty() {
out.insert_str(
0,
"<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
<span class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
);
out.push_str("</code></span></span></span></span>");
if out.is_empty() {
write!(&mut out, "</code></pre>",);
}

out.into_inner()
(format!("{:#}", ty.print(cx)), out.into_inner())
}

pub(crate) fn notable_traits_json<'a>(
tys: impl Iterator<Item = &'a clean::Type>,
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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)]
Expand Down
24 changes: 19 additions & 5 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ use std::rc::Rc;

use super::{
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item,
render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters,
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
render_impl, render_rightside, render_stability_since_raw, AssocItemLink, Context,
ImplRenderingParameters,
};
use crate::clean;
use crate::config::ModuleSorting;
Expand Down Expand Up @@ -183,6 +184,16 @@ pub(super) fn print_item(
unreachable!();
}
}

// Render notable-traits.js used for all methods in this module.
if !cx.types_with_notable_traits.is_empty() {
write!(
buf,
r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
notable_traits_json(cx.types_with_notable_traits.iter(), cx)
);
cx.types_with_notable_traits.clear();
}
}

/// For large structs, enums, unions, etc, determine whether to hide their fields
Expand Down Expand Up @@ -516,6 +527,9 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
+ name.as_str().len()
+ generics_len;

let notable_traits =
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));

wrap_into_item_decl(w, |w| {
wrap_item(w, "fn", |w| {
render_attributes_in_pre(w, it, "");
Expand All @@ -533,11 +547,11 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
generics = f.generics.print(cx),
where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
decl = f.decl.full_print(header_len, 0, cx),
notable_traits = notable_traits_decl(&f.decl, cx),
notable_traits = notable_traits.unwrap_or_default(),
);
});
});
document(w, cx, it, None, HeadingOffset::H2)
document(w, cx, it, None, HeadingOffset::H2);
}

fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) {
Expand Down
6 changes: 6 additions & 0 deletions src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ nav.sub {
.source .sidebar {
display: none;
}

.notable-traits {
/* layout requires javascript
https://github.com/rust-lang/rust/issues/102576 */
display: none;
}
Loading

0 comments on commit 206928c

Please sign in to comment.