Skip to content

Commit

Permalink
rustdoc: make JS trait impls act more like HTML
Browse files Browse the repository at this point in the history
  • Loading branch information
notriddle committed Oct 7, 2023
1 parent 67e3eea commit 760c7f0
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 6 deletions.
21 changes: 19 additions & 2 deletions src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,20 +529,37 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
.values()
.flat_map(|AliasedTypeImpl { impl_, type_aliases }| {
let mut ret = Vec::new();
let trait_ = impl_.inner_impl().trait_.as_ref().map(|path| path.last().to_string());
let trait_ = impl_
.inner_impl()
.trait_
.as_ref()
.map(|trait_| format!("{:#}", trait_.print(cx)));
// render_impl will filter out "impossible-to-call" methods
// to make that functionality work here, it needs to be called with
// each type alias, and if it gives a different result, split the impl
for &(type_alias_fqp, ref type_alias_item) in type_aliases {
let mut buf = Buffer::html();
cx.id_map = Default::default();
cx.deref_id_map = Default::default();
let target_did = impl_
.inner_impl()
.trait_
.as_ref()
.map(|trait_| trait_.def_id())
.or_else(|| impl_.inner_impl().for_.def_id(cache));
let provided_methods;
let assoc_link = if let Some(target_did) = target_did {
provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx());
AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods)
} else {
AssocItemLink::Anchor(None)
};
super::render_impl(
&mut buf,
cx,
*impl_,
&type_alias_item,
AssocItemLink::Anchor(None),
assoc_link,
RenderMode::Normal,
None,
&[],
Expand Down
15 changes: 12 additions & 3 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,12 +628,14 @@ function preLoadCss(cssUrl) {

let implementations = document.getElementById("implementations-list");
let trait_implementations = document.getElementById("trait-implementations-list");
let trait_implementations_header = document.getElementById("trait-implementations");

// We want to include the current type alias's impls, and no others.
const script = document.querySelector("script[data-self-path]");
const selfPath = script ? script.getAttribute("data-self-path") : null;

// These sidebar blocks need filled in, too.
const mainContent = document.querySelector("#main-content");
const sidebarSection = document.querySelector(".sidebar section");
let methods = document.querySelector(".sidebar .block.method");
let associatedTypes = document.querySelector(".sidebar .block.associatedtype");
Expand Down Expand Up @@ -667,18 +669,18 @@ function preLoadCss(cssUrl) {
const h = document.createElement("h3");
h.appendChild(link);
trait_implementations = outputList;
trait_implementations_header = outputListHeader;
sidebarSection.appendChild(h);
sidebarTraitList = document.createElement("ul");
sidebarTraitList.className = "block trait-implementation";
sidebarSection.appendChild(sidebarTraitList);
const mainContent = document.querySelector("#main-content");
mainContent.appendChild(outputListHeader);
mainContent.appendChild(outputList);
} else {
implementations = outputList;
if (trait_implementations) {
document.insertBefore(outputListHeader, trait_implementations);
document.insertBefore(outputList, trait_implementations);
mainContent.insertBefore(outputListHeader, trait_implementations_header);
mainContent.insertBefore(outputList, trait_implementations_header);
} else {
const mainContent = document.querySelector("#main-content");
mainContent.appendChild(outputListHeader);
Expand Down Expand Up @@ -710,7 +712,14 @@ function preLoadCss(cssUrl) {
}
}
if (i !== 0) {
const oldHref = `#${el.id}`;
const newHref = `#${el.id}-${i}`;
el.id = `${el.id}-${i}`;
onEachLazy(template.content.querySelectorAll("a[href]"), link => {
if (link.getAttribute("href") === oldHref) {
link.href = newHref;
}
});
}
idMap.set(el.id, i + 1);
});
Expand Down
20 changes: 20 additions & 0 deletions tests/rustdoc-gui/src/test_docs/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,26 @@ impl SomeOtherTypeWithMethodsAndInlining {
pub fn some_other_method_directly(&self) {}
}

/// Another type alias, this time with methods.
pub struct UnderlyingFooBarBaz;
pub type SomeOtherTypeWithMethodsAndInliningAndTraits = UnderlyingFooBarBaz;

impl AsRef<str> for UnderlyingFooBarBaz {
fn as_ref(&self) -> &str {
"hello"
}
}

impl UnderlyingFooBarBaz {
pub fn inherent_fn(&self) {}
}

impl AsRef<u8> for SomeOtherTypeWithMethodsAndInliningAndTraits {
fn as_ref(&self) -> &u8 {
b"hello"
}
}

pub mod huge_amount_of_consts {
include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
}
Expand Down
49 changes: 48 additions & 1 deletion tests/rustdoc-gui/type-impls.goml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,39 @@ assert-text: (".block.method li:nth-child(2)", 'some_other_method_directly')
assert-text: (".block.method li:nth-child(3)", 'warning1')
assert-text: (".block.method li:nth-child(4)", 'warning2')

// Now try trait implementation merging and duplicate renumbering
go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInliningAndTraits.html"

// method directly on type alias
assert: "//*[@id='method.as_ref']"
assert-count: ("//*[@id='method.as_ref']", 1)
// method on underlying type
assert: "//*[@id='method.as_ref-1']"

// sidebar items
assert-count: (
"//*[@class='sidebar-elems']//h3/a[@href='#trait-implementations']",
1
)
assert-text: ("//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cstr%3E-for-UnderlyingFooBarBaz']", "AsRef<str>")
assert-text: (
"//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cu8%3E-for-SomeOtherTypeWithMethodsAndInliningAndTraits']",
"AsRef<u8>"
)
assert-count: ("#trait-implementations-list", 1)
assert-count: ("#trait-implementations-list > details", 2)
// Both links point at the underlying trait
store-property: ("//*[@id='method.as_ref']//a[@class='fn']", {"href": href})
assert-property: ("//*[@id='method.as_ref-1']//a[@class='fn']", {"href": |href|})
// Both links have a self-anchor
assert: "//*[@id='method.as_ref']//a[@class='anchor'][@href='#method.as_ref']"
assert: "//*[@id='method.as_ref-1']//a[@class='anchor'][@href='#method.as_ref-1']"

///////////////////////////////////////////////////////////////////////////
// Now, if JavaScript is disabled, only the first method will be present //
///////////////////////////////////////////////////////////////////////////
javascript: false
reload:
go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInlining.html"

// method directly on type alias
wait-for: "//*[@id='method.some_other_method_directly']"
Expand All @@ -37,3 +65,22 @@ wait-for: "//*[@id='method.some_other_method_directly']"
assert-false: "//*[@id='method.must_use']"
assert-false: "//*[@id='method.warning1']"
assert-false: "//*[@id='method.warning2']"

// Now try trait implementation merging and duplicate renumbering
go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInliningAndTraits.html"

// methods directly on type alias
assert: "//*[@id='method.as_ref']"
assert-count: ("//*[@id='method.as_ref']", 1)
// method on target type
assert-false: "//*[@id='method.as_ref-1']"

// sidebar items
assert-count: (
"//*[@class='sidebar-elems']//h3/a[@href='#trait-implementations']",
1
)
assert-false: "//a[@href='#impl-AsRef%3Cstr%3E-for-UnderlyingFooBarBaz']"
assert: "//a[@href='#impl-AsRef%3Cu8%3E-for-SomeOtherTypeWithMethodsAndInliningAndTraits']"
assert-count: ("#trait-implementations-list", 1)
assert-count: ("#trait-implementations-list > details", 1)

0 comments on commit 760c7f0

Please sign in to comment.