mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
Recursively document methods via Deref
traits
This commit is contained in:
parent
61c8aae0a9
commit
fd0ad03902
@ -3548,9 +3548,6 @@ fn render_assoc_items(
|
||||
);
|
||||
}
|
||||
}
|
||||
if let AssocItemRender::DerefFor { .. } = what {
|
||||
return;
|
||||
}
|
||||
if !traits.is_empty() {
|
||||
let deref_impl =
|
||||
traits.iter().find(|t| t.inner_impl().trait_.def_id() == cache.deref_trait_did);
|
||||
@ -3560,6 +3557,12 @@ fn render_assoc_items(
|
||||
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, cache);
|
||||
}
|
||||
|
||||
// If we were already one level into rendering deref methods, we don't want to render
|
||||
// anything after recursing into any further deref methods above.
|
||||
if let AssocItemRender::DerefFor { .. } = what {
|
||||
return;
|
||||
}
|
||||
|
||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
||||
traits.iter().partition(|t| t.inner_impl().synthetic);
|
||||
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
|
||||
@ -3631,6 +3634,13 @@ fn render_deref_methods(
|
||||
let what =
|
||||
AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
|
||||
if let Some(did) = target.def_id() {
|
||||
if let Some(type_did) = impl_.inner_impl().for_.def_id() {
|
||||
// `impl Deref<Target = S> for S`
|
||||
if did == type_did {
|
||||
// Avoid infinite cycles
|
||||
return;
|
||||
}
|
||||
}
|
||||
render_assoc_items(w, cx, container_item, did, what, cache);
|
||||
} else {
|
||||
if let Some(prim) = target.primitive_type() {
|
||||
@ -4417,6 +4427,26 @@ fn sidebar_deref_methods(impl_: &Impl, v: &Vec<Impl>) -> String {
|
||||
out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret.join("")));
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into any further impls that might exist for `target`
|
||||
if let Some(target_did) = target.def_id() {
|
||||
if let Some(target_impls) = c.impls.get(&target_did) {
|
||||
if let Some(target_deref_impl) = target_impls
|
||||
.iter()
|
||||
.filter(|i| i.inner_impl().trait_.is_some())
|
||||
.find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did)
|
||||
{
|
||||
if let Some(type_did) = impl_.inner_impl().for_.def_id() {
|
||||
// `impl Deref<Target = S> for S`
|
||||
if target_did == type_did {
|
||||
// Avoid infinite cycles
|
||||
return out;
|
||||
}
|
||||
}
|
||||
out.push_str(&sidebar_deref_methods(target_deref_impl, target_impls));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
|
17
src/test/rustdoc-ui/deref-recursive-cycle.rs
Normal file
17
src/test/rustdoc-ui/deref-recursive-cycle.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// check-pass
|
||||
// #26207: Ensure `Deref` cycles are properly handled without errors.
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct S;
|
||||
|
||||
impl std::ops::Deref for S {
|
||||
type Target = S;
|
||||
|
||||
fn deref(&self) -> &S {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s: S = *******S;
|
||||
}
|
40
src/test/rustdoc/deref-recursive.rs
Normal file
40
src/test/rustdoc/deref-recursive.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
|
||||
// levels if needed.
|
||||
|
||||
// @has 'foo/struct.Foo.html'
|
||||
// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = Bar>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
|
||||
// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = Baz>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
|
||||
// @has '-' '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Bar>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
|
||||
// @has '-' '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Baz>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
pub struct Foo(Bar);
|
||||
pub struct Bar(Baz);
|
||||
pub struct Baz;
|
||||
|
||||
impl Deref for Foo {
|
||||
type Target = Bar;
|
||||
fn deref(&self) -> &Bar { &self.0 }
|
||||
}
|
||||
|
||||
impl Deref for Bar {
|
||||
type Target = Baz;
|
||||
fn deref(&self) -> &Baz { &self.0 }
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
/// This appears under `Foo` methods
|
||||
pub fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl Baz {
|
||||
/// This should also appear in `Foo` methods when recursing
|
||||
pub fn baz(&self) {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user