Add tests for recursive deref

This commit is contained in:
Guillaume Gomez 2021-10-22 22:39:33 +02:00
parent 8a473ca346
commit 0c38f31bf2
7 changed files with 169 additions and 8 deletions

View file

@ -81,8 +81,8 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items {
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
if cleaner.keep_impl(for_)
&& trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
&& cleaner.keep_impl(for_)
{
let target = items
.iter()
@ -221,8 +221,11 @@ impl BadImplStripper {
true
} else if let Some(prim) = ty.primitive_type() {
self.prims.contains(&prim)
} else if let Some(did) = ty.def_id_no_primitives() {
self.keep_impl_with_def_id(did.into())
} else if ty.def_id_no_primitives().is_some() {
// We want to keep *ALL* deref implementations in case some of them are used in
// the current crate.
// FIXME: Try to filter the one actually used...
true
} else {
false
}

View file

@ -0,0 +1,19 @@
// check-pass
// ICE found in https://github.com/rust-lang/rust/issues/83123
pub struct Attribute;
pub struct Map<'hir> {}
impl<'hir> Map<'hir> {
pub fn attrs(&self) -> &'hir [Attribute] { &[] }
}
pub struct List<T>(T);
impl<T> std::ops::Deref for List<T> {
type Target = [T];
fn deref(&self) -> &[T] {
&[]
}
}

View file

@ -0,0 +1,24 @@
// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
// levels and across multiple crates.
// @has 'foo/struct.Foo.html'
// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
#![crate_name = "foo"]
use std::ops::Deref;
use std::path::PathBuf;
pub struct Foo(PathBuf);
impl Deref for Foo {
type Target = PathBuf;
fn deref(&self) -> &PathBuf { &self.0 }
}

View 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-Bar"]' 'Methods from Deref<Target = Bar>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' '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) {}
}

View file

@ -1,12 +1,12 @@
#![crate_name = "foo"]
// @has 'foo/struct.Bar.html'
// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'

View file

@ -15,7 +15,7 @@ impl Deref for A {
fn deref(&self) -> &B { todo!() }
}
// @!has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
impl Deref for B {
type Target = C;
fn deref(&self) -> &C { todo!() }

View file

@ -1,7 +1,9 @@
use std::ops::Deref;
// Cyclic deref with the parent (which is not the top parent).
pub struct A;
pub struct B;
pub struct C;
// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
impl Deref for A {
@ -14,7 +16,80 @@ impl Deref for A {
// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
impl Deref for B {
type Target = A;
type Target = C;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
impl Deref for C {
type Target = B;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// Cyclic deref with the grand-parent (which is not the top parent).
pub struct D;
pub struct E;
pub struct F;
pub struct G;
// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
impl Deref for D {
type Target = E;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
impl Deref for E {
type Target = F;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
impl Deref for F {
type Target = G;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
impl Deref for G {
type Target = E;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// Cyclic deref with top parent.
pub struct H;
pub struct I;
// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
impl Deref for H {
type Target = I;
fn deref(&self) -> &Self::Target {
panic!()
}
}
// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
impl Deref for I {
type Target = H;
fn deref(&self) -> &Self::Target {
panic!()