rustdoc: make JS trait impls act more like HTML

This commit is contained in:
Michael Howell 2023-10-06 23:31:16 -07:00
parent 62c67a6438
commit 46fdeb24fd
6 changed files with 100 additions and 8 deletions

View File

@ -55,7 +55,6 @@
use rustc_hir::Mutability; use rustc_hir::Mutability;
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_span::{ use rustc_span::{
symbol::{sym, Symbol}, symbol::{sym, Symbol},
BytePos, FileName, RealFileName, BytePos, FileName, RealFileName,

View File

@ -530,7 +530,11 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
.values() .values()
.flat_map(|AliasedTypeImpl { impl_, type_aliases }| { .flat_map(|AliasedTypeImpl { impl_, type_aliases }| {
let mut ret = Vec::new(); 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 // render_impl will filter out "impossible-to-call" methods
// to make that functionality work here, it needs to be called with // 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 // each type alias, and if it gives a different result, split the impl
@ -538,12 +542,25 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
let mut buf = Buffer::html(); let mut buf = Buffer::html();
cx.id_map = Default::default(); cx.id_map = Default::default();
cx.deref_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( super::render_impl(
&mut buf, &mut buf,
cx, cx,
*impl_, *impl_,
&type_alias_item, &type_alias_item,
AssocItemLink::Anchor(None), assoc_link,
RenderMode::Normal, RenderMode::Normal,
None, None,
&[], &[],

View File

@ -680,12 +680,14 @@ function preLoadCss(cssUrl) {
let implementations = document.getElementById("implementations-list"); let implementations = document.getElementById("implementations-list");
let trait_implementations = document.getElementById("trait-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. // We want to include the current type alias's impls, and no others.
const script = document.querySelector("script[data-self-path]"); const script = document.querySelector("script[data-self-path]");
const selfPath = script ? script.getAttribute("data-self-path") : null; const selfPath = script ? script.getAttribute("data-self-path") : null;
// These sidebar blocks need filled in, too. // These sidebar blocks need filled in, too.
const mainContent = document.querySelector("#main-content");
const sidebarSection = document.querySelector(".sidebar section"); const sidebarSection = document.querySelector(".sidebar section");
let methods = document.querySelector(".sidebar .block.method"); let methods = document.querySelector(".sidebar .block.method");
let associatedTypes = document.querySelector(".sidebar .block.associatedtype"); let associatedTypes = document.querySelector(".sidebar .block.associatedtype");
@ -719,18 +721,18 @@ function preLoadCss(cssUrl) {
const h = document.createElement("h3"); const h = document.createElement("h3");
h.appendChild(link); h.appendChild(link);
trait_implementations = outputList; trait_implementations = outputList;
trait_implementations_header = outputListHeader;
sidebarSection.appendChild(h); sidebarSection.appendChild(h);
sidebarTraitList = document.createElement("ul"); sidebarTraitList = document.createElement("ul");
sidebarTraitList.className = "block trait-implementation"; sidebarTraitList.className = "block trait-implementation";
sidebarSection.appendChild(sidebarTraitList); sidebarSection.appendChild(sidebarTraitList);
const mainContent = document.querySelector("#main-content");
mainContent.appendChild(outputListHeader); mainContent.appendChild(outputListHeader);
mainContent.appendChild(outputList); mainContent.appendChild(outputList);
} else { } else {
implementations = outputList; implementations = outputList;
if (trait_implementations) { if (trait_implementations) {
document.insertBefore(outputListHeader, trait_implementations); mainContent.insertBefore(outputListHeader, trait_implementations_header);
document.insertBefore(outputList, trait_implementations); mainContent.insertBefore(outputList, trait_implementations_header);
} else { } else {
const mainContent = document.querySelector("#main-content"); const mainContent = document.querySelector("#main-content");
mainContent.appendChild(outputListHeader); mainContent.appendChild(outputListHeader);
@ -762,7 +764,14 @@ function preLoadCss(cssUrl) {
} }
} }
if (i !== 0) { if (i !== 0) {
const oldHref = `#${el.id}`;
const newHref = `#${el.id}-${i}`;
el.id = `${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); idMap.set(el.id, i + 1);
}); });

View File

@ -167,6 +167,26 @@ impl SomeOtherTypeWithMethodsAndInlining {
pub fn some_other_method_directly(&self) {} 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 { pub mod huge_amount_of_consts {
include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs")); include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
} }

View File

@ -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(3)", 'warning1')
assert-text: (".block.method li:nth-child(4)", 'warning2') 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-UnderlyingFooBarBaz']",
"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 // // Now, if JavaScript is disabled, only the first method will be present //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
javascript: false javascript: false
reload: go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInlining.html"
// method directly on type alias // method directly on type alias
wait-for: "//*[@id='method.some_other_method_directly']" wait-for: "//*[@id='method.some_other_method_directly']"
@ -37,3 +65,22 @@ wait-for: "//*[@id='method.some_other_method_directly']"
assert-false: "//*[@id='method.must_use']" assert-false: "//*[@id='method.must_use']"
assert-false: "//*[@id='method.warning1']" assert-false: "//*[@id='method.warning1']"
assert-false: "//*[@id='method.warning2']" 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-UnderlyingFooBarBaz']"
assert-count: ("#trait-implementations-list", 1)
assert-count: ("#trait-implementations-list > details", 1)

View File

@ -22,7 +22,7 @@ impl Bar for GenericStruct<u32> {}
// We check that "Aliased type" is also present as a title in the sidebar. // We check that "Aliased type" is also present as a title in the sidebar.
// @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type' // @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type'
// We check that we have the implementation of the type alias itself. // We check that we have the implementation of the type alias itself.
// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct' // @has - '//*[@id="impl-GenericStruct%3Cu8%3E"]/h3' 'impl TypedefStruct'
// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' // @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()'
// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs. // This trait implementation doesn't match the type alias parameters so shouldn't appear in docs.
// @!has - '//h3' 'impl Bar for GenericStruct<u32> {}' // @!has - '//h3' 'impl Bar for GenericStruct<u32> {}'