adapted from 513756bb55a0dbc6e74d0043afd1727bd3c73aae
This commit is contained in:
parent
381f1318ad
commit
e917d2f1ea
|
@ -5,8 +5,7 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::{LOCAL_CRATE};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
|
@ -53,9 +52,6 @@ crate struct Context<'tcx> {
|
|||
pub(super) render_redirect_pages: bool,
|
||||
/// The map used to ensure all generated 'id=' attributes are unique.
|
||||
pub(super) id_map: RefCell<IdMap>,
|
||||
/// Tracks section IDs for `Deref` targets so they match in both the main
|
||||
/// body and the sidebar.
|
||||
pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
|
||||
/// Shared mutable state.
|
||||
///
|
||||
/// Issue for improving the situation: [#82381][]
|
||||
|
@ -76,7 +72,7 @@ crate struct Context<'tcx> {
|
|||
|
||||
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
rustc_data_structures::static_assert_size!(Context<'_>, 152);
|
||||
rustc_data_structures::static_assert_size!(Context<'_>, 112);
|
||||
|
||||
impl<'tcx> Context<'tcx> {
|
||||
pub(super) fn path(&self, filename: &str) -> PathBuf {
|
||||
|
@ -416,7 +412,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||
dst,
|
||||
render_redirect_pages: false,
|
||||
id_map: RefCell::new(id_map),
|
||||
deref_id_map: RefCell::new(FxHashMap::default()),
|
||||
shared: Rc::new(scx),
|
||||
cache: Rc::new(cache),
|
||||
};
|
||||
|
@ -439,7 +434,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
|||
dst: self.dst.clone(),
|
||||
render_redirect_pages: self.render_redirect_pages,
|
||||
id_map: RefCell::new(id_map),
|
||||
deref_id_map: RefCell::new(FxHashMap::default()),
|
||||
shared: Rc::clone(&self.shared),
|
||||
cache: Rc::clone(&self.cache),
|
||||
}
|
||||
|
|
|
@ -1159,21 +1159,12 @@ fn render_assoc_items(
|
|||
RenderMode::Normal
|
||||
}
|
||||
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
|
||||
let id = cx.derive_id(small_url_encode(format!(
|
||||
"deref-methods-{:#}",
|
||||
type_.print(cx.cache())
|
||||
)));
|
||||
debug!("Adding {} to deref id map", type_.print(cx.cache()));
|
||||
cx.deref_id_map
|
||||
.borrow_mut()
|
||||
.insert(type_.def_id_full(cx.cache()).unwrap(), id.clone());
|
||||
write!(
|
||||
w,
|
||||
"<h2 id=\"{id}\" class=\"small-section-header\">\
|
||||
"<h2 id=\"deref-methods\" class=\"small-section-header\">\
|
||||
Methods from {trait_}<Target = {type_}>\
|
||||
<a href=\"#{id}\" class=\"anchor\"></a>\
|
||||
<a href=\"#deref-methods\" class=\"anchor\"></a>\
|
||||
</h2>",
|
||||
id = id,
|
||||
trait_ = trait_.print(cx.cache()),
|
||||
type_ = type_.print(cx.cache()),
|
||||
);
|
||||
|
@ -1198,6 +1189,9 @@ fn render_assoc_items(
|
|||
);
|
||||
}
|
||||
}
|
||||
if let AssocItemRender::DerefFor { .. } = what {
|
||||
return;
|
||||
}
|
||||
if !traits.is_empty() {
|
||||
let deref_impl = traits
|
||||
.iter()
|
||||
|
@ -1208,13 +1202,6 @@ fn render_assoc_items(
|
|||
});
|
||||
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
|
||||
}
|
||||
|
||||
// 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>, _) =
|
||||
|
@ -2020,14 +2007,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
|
|||
.flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
|
||||
.collect::<Vec<_>>();
|
||||
if !ret.is_empty() {
|
||||
let deref_id_map = cx.deref_id_map.borrow();
|
||||
let id = deref_id_map
|
||||
.get(&real_target.def_id_full(cx.cache()).unwrap())
|
||||
.expect("Deref section without derived id");
|
||||
write!(
|
||||
out,
|
||||
"<a class=\"sidebar-title\" href=\"#{}\">Methods from {}<Target={}></a>",
|
||||
id,
|
||||
"<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}<Target={}></a>",
|
||||
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(c))),
|
||||
Escape(&format!("{:#}", real_target.print(c))),
|
||||
);
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::clean::*;
|
|||
use crate::core::DocContext;
|
||||
use crate::fold::DocFolder;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::fx::{FxHashSet};
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_span::symbol::sym;
|
||||
|
@ -53,6 +53,39 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
|||
}
|
||||
}
|
||||
|
||||
let mut cleaner = BadImplStripper { prims, items: crate_items };
|
||||
|
||||
// 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_.def_id() == cx.tcx.lang_items().deref_trait() {
|
||||
let target = items
|
||||
.iter()
|
||||
.find_map(|item| match *item.kind {
|
||||
TypedefItem(ref t, true) => Some(&t.type_),
|
||||
_ => None,
|
||||
})
|
||||
.expect("Deref impl without Target type");
|
||||
|
||||
if let Some(prim) = target.primitive_type() {
|
||||
cleaner.prims.insert(prim);
|
||||
} else if let Some(did) = target.def_id() {
|
||||
cleaner.items.insert(did);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_items.retain(|it| {
|
||||
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
|
||||
cleaner.keep_impl(for_)
|
||||
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
|
||||
|| blanket_impl.is_some()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
|
||||
// doesn't work with it anyway, so pull them from the HIR map instead
|
||||
let mut extra_attrs = Vec::new();
|
||||
|
@ -84,53 +117,6 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
|||
}
|
||||
}
|
||||
|
||||
let mut cleaner = BadImplStripper { prims, items: crate_items };
|
||||
|
||||
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
|
||||
// Gather all type to `Deref` target edges.
|
||||
for it in &new_items {
|
||||
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
|
||||
if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
|
||||
let target = items.iter().find_map(|item| match *item.kind {
|
||||
TypedefItem(ref t, true) => Some(&t.type_),
|
||||
_ => None,
|
||||
});
|
||||
if let (Some(for_did), Some(target)) = (for_.def_id(), target) {
|
||||
type_did_to_deref_target.insert(for_did, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Follow all `Deref` targets of included items and recursively add them as valid
|
||||
fn add_deref_target(
|
||||
map: &FxHashMap<DefId, &Type>,
|
||||
cleaner: &mut BadImplStripper,
|
||||
type_did: &DefId,
|
||||
) {
|
||||
if let Some(target) = map.get(type_did) {
|
||||
debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
|
||||
if let Some(target_prim) = target.primitive_type() {
|
||||
cleaner.prims.insert(target_prim);
|
||||
} else if let Some(target_did) = target.def_id() {
|
||||
// `impl Deref<Target = S> for S`
|
||||
if target_did == *type_did {
|
||||
// Avoid infinite cycles
|
||||
return;
|
||||
}
|
||||
cleaner.items.insert(target_did);
|
||||
add_deref_target(map, cleaner, &target_did);
|
||||
}
|
||||
}
|
||||
}
|
||||
for type_did in type_did_to_deref_target.keys() {
|
||||
// Since only the `DefId` portion of the `Type` instances is known to be same for both the
|
||||
// `Deref` target type and the impl for type positions, this map of types is keyed by
|
||||
// `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
|
||||
if cleaner.keep_impl_with_def_id(type_did) {
|
||||
add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
|
||||
}
|
||||
}
|
||||
|
||||
let items = if let Some(ref mut it) = krate.module {
|
||||
if let ModuleItem(Module { ref mut items, .. }) = *it.kind {
|
||||
items
|
||||
|
@ -142,18 +128,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
|||
};
|
||||
|
||||
items.extend(synth_impls);
|
||||
for it in new_items.drain(..) {
|
||||
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
|
||||
if !(cleaner.keep_impl(for_)
|
||||
|| trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
|
||||
|| blanket_impl.is_some())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
items.push(it);
|
||||
}
|
||||
items.extend(new_items);
|
||||
|
||||
krate
|
||||
}
|
||||
|
@ -208,13 +183,9 @@ impl BadImplStripper {
|
|||
} else if let Some(prim) = ty.primitive_type() {
|
||||
self.prims.contains(&prim)
|
||||
} else if let Some(did) = ty.def_id() {
|
||||
self.keep_impl_with_def_id(&did)
|
||||
self.items.contains(&did)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn keep_impl_with_def_id(&self, did: &DefId) -> bool {
|
||||
self.items.contains(did)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// 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;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
// #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"][@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
|
||||
// @has '-' '//*[@class="sidebar-title"][@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 }
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
// #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"][@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
|
||||
// @has '-' '//*[@class="sidebar-title"][@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) {}
|
||||
}
|
|
@ -3,12 +3,12 @@
|
|||
#![crate_name = "foo"]
|
||||
|
||||
// @has 'foo/struct.Bar.html'
|
||||
// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
|
||||
// @has '-' '//*[@id="deref-methods"]' '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"][@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
|
||||
// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods"]' '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'
|
||||
|
|
Loading…
Reference in New Issue