Skip to content

Commit 0a3e700

Browse files
committed
rustdoc: Inline methods inhereted through Deref
Whenever a type implements Deref, rustdoc will now add a section to the "methods available" sections for "Methods from Deref<Target=Foo>", listing all the inherent methods of the type `Foo`. Closes #19190
1 parent bf1ecd7 commit 0a3e700

File tree

9 files changed

+323
-61
lines changed

9 files changed

+323
-61
lines changed

src/librustdoc/clean/inline.rs

+29-20
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,17 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn
218218
})
219219
}
220220

221-
fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
222-
did: ast::DefId) -> Vec<clean::Item> {
221+
pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
222+
did: ast::DefId) -> Vec<clean::Item> {
223223
ty::populate_implementations_for_type_if_necessary(tcx, did);
224224
let mut impls = Vec::new();
225225

226226
match tcx.inherent_impls.borrow().get(&did) {
227227
None => {}
228228
Some(i) => {
229-
impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) }));
229+
for &did in i.iter() {
230+
build_impl(cx, tcx, did, &mut impls);
231+
}
230232
}
231233
}
232234

@@ -247,9 +249,9 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
247249

248250
fn populate_impls(cx: &DocContext, tcx: &ty::ctxt,
249251
def: decoder::DefLike,
250-
impls: &mut Vec<Option<clean::Item>>) {
252+
impls: &mut Vec<clean::Item>) {
251253
match def {
252-
decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)),
254+
decoder::DlImpl(did) => build_impl(cx, tcx, did, impls),
253255
decoder::DlDef(def::DefMod(did)) => {
254256
csearch::each_child_of_item(&tcx.sess.cstore,
255257
did,
@@ -262,14 +264,15 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
262264
}
263265
}
264266

265-
impls.into_iter().filter_map(|a| a).collect()
267+
return impls;
266268
}
267269

268-
fn build_impl(cx: &DocContext,
269-
tcx: &ty::ctxt,
270-
did: ast::DefId) -> Option<clean::Item> {
270+
pub fn build_impl(cx: &DocContext,
271+
tcx: &ty::ctxt,
272+
did: ast::DefId,
273+
ret: &mut Vec<clean::Item>) {
271274
if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
272-
return None
275+
return
273276
}
274277

275278
let attrs = load_attrs(cx, tcx, did);
@@ -278,13 +281,13 @@ fn build_impl(cx: &DocContext,
278281
// If this is an impl for a #[doc(hidden)] trait, be sure to not inline
279282
let trait_attrs = load_attrs(cx, tcx, t.def_id);
280283
if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
281-
return None
284+
return
282285
}
283286
}
284287

285288
// If this is a defaulted impl, then bail out early here
286289
if csearch::is_default_impl(&tcx.sess.cstore, did) {
287-
return Some(clean::Item {
290+
return ret.push(clean::Item {
288291
inner: clean::DefaultImplItem(clean::DefaultImpl {
289292
// FIXME: this should be decoded
290293
unsafety: ast::Unsafety::Normal,
@@ -352,19 +355,25 @@ fn build_impl(cx: &DocContext,
352355
})
353356
}
354357
}
355-
}).collect();
358+
}).collect::<Vec<_>>();
356359
let polarity = csearch::get_impl_polarity(tcx, did);
357360
let ty = ty::lookup_item_type(tcx, did);
358-
return Some(clean::Item {
361+
let trait_ = associated_trait.clean(cx).map(|bound| {
362+
match bound {
363+
clean::TraitBound(polyt, _) => polyt.trait_,
364+
clean::RegionBound(..) => unreachable!(),
365+
}
366+
});
367+
if let Some(clean::ResolvedPath { did, .. }) = trait_ {
368+
if Some(did) == cx.deref_trait_did.get() {
369+
super::build_deref_target_impls(cx, &trait_items, ret);
370+
}
371+
}
372+
ret.push(clean::Item {
359373
inner: clean::ImplItem(clean::Impl {
360374
unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded
361375
derived: clean::detect_derived(&attrs),
362-
trait_: associated_trait.clean(cx).map(|bound| {
363-
match bound {
364-
clean::TraitBound(polyt, _) => polyt.trait_,
365-
clean::RegionBound(..) => unreachable!(),
366-
}
367-
}),
376+
trait_: trait_,
368377
for_: ty.ty.clean(cx),
369378
generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
370379
items: trait_items,

src/librustdoc/clean/mod.rs

+76-6
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
128128
fn clean(&self, cx: &DocContext) -> Crate {
129129
use rustc::session::config::Input;
130130

131+
if let Some(t) = cx.tcx_opt() {
132+
cx.deref_trait_did.set(t.lang_items.deref_trait());
133+
}
134+
131135
let mut externs = Vec::new();
132136
cx.sess().cstore.iter_crate_data(|n, meta| {
133137
externs.push((n, meta.clean(cx)));
@@ -387,7 +391,7 @@ impl Clean<Item> for doctree::Module {
387391
items.extend(self.statics.iter().map(|x| x.clean(cx)));
388392
items.extend(self.constants.iter().map(|x| x.clean(cx)));
389393
items.extend(self.traits.iter().map(|x| x.clean(cx)));
390-
items.extend(self.impls.iter().map(|x| x.clean(cx)));
394+
items.extend(self.impls.iter().flat_map(|x| x.clean(cx).into_iter()));
391395
items.extend(self.macros.iter().map(|x| x.clean(cx)));
392396
items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
393397

@@ -2186,9 +2190,21 @@ fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
21862190
attr::contains_name(attrs, "automatically_derived")
21872191
}
21882192

2189-
impl Clean<Item> for doctree::Impl {
2190-
fn clean(&self, cx: &DocContext) -> Item {
2191-
Item {
2193+
impl Clean<Vec<Item>> for doctree::Impl {
2194+
fn clean(&self, cx: &DocContext) -> Vec<Item> {
2195+
let mut ret = Vec::new();
2196+
let trait_ = self.trait_.clean(cx);
2197+
let items = self.items.clean(cx);
2198+
2199+
// If this impl block is an implementation of the Deref trait, then we
2200+
// need to try inlining the target's inherent impl blocks as well.
2201+
if let Some(ResolvedPath { did, .. }) = trait_ {
2202+
if Some(did) == cx.deref_trait_did.get() {
2203+
build_deref_target_impls(cx, &items, &mut ret);
2204+
}
2205+
}
2206+
2207+
ret.push(Item {
21922208
name: None,
21932209
attrs: self.attrs.clean(cx),
21942210
source: self.whence.clean(cx),
@@ -2198,12 +2214,66 @@ impl Clean<Item> for doctree::Impl {
21982214
inner: ImplItem(Impl {
21992215
unsafety: self.unsafety,
22002216
generics: self.generics.clean(cx),
2201-
trait_: self.trait_.clean(cx),
2217+
trait_: trait_,
22022218
for_: self.for_.clean(cx),
2203-
items: self.items.clean(cx),
2219+
items: items,
22042220
derived: detect_derived(&self.attrs),
22052221
polarity: Some(self.polarity.clean(cx)),
22062222
}),
2223+
});
2224+
return ret;
2225+
}
2226+
}
2227+
2228+
fn build_deref_target_impls(cx: &DocContext,
2229+
items: &[Item],
2230+
ret: &mut Vec<Item>) {
2231+
let tcx = match cx.tcx_opt() {
2232+
Some(t) => t,
2233+
None => return,
2234+
};
2235+
2236+
for item in items {
2237+
let target = match item.inner {
2238+
TypedefItem(ref t) => &t.type_,
2239+
_ => continue,
2240+
};
2241+
let primitive = match *target {
2242+
ResolvedPath { did, .. } if ast_util::is_local(did) => continue,
2243+
ResolvedPath { did, .. } => {
2244+
ret.extend(inline::build_impls(cx, tcx, did));
2245+
continue
2246+
}
2247+
_ => match target.primitive_type() {
2248+
Some(prim) => prim,
2249+
None => continue,
2250+
}
2251+
};
2252+
let did = match primitive {
2253+
Isize => tcx.lang_items.isize_impl(),
2254+
I8 => tcx.lang_items.i8_impl(),
2255+
I16 => tcx.lang_items.i16_impl(),
2256+
I32 => tcx.lang_items.i32_impl(),
2257+
I64 => tcx.lang_items.i64_impl(),
2258+
Usize => tcx.lang_items.usize_impl(),
2259+
U8 => tcx.lang_items.u8_impl(),
2260+
U16 => tcx.lang_items.u16_impl(),
2261+
U32 => tcx.lang_items.u32_impl(),
2262+
U64 => tcx.lang_items.u64_impl(),
2263+
F32 => tcx.lang_items.f32_impl(),
2264+
F64 => tcx.lang_items.f64_impl(),
2265+
Char => tcx.lang_items.char_impl(),
2266+
Bool => None,
2267+
Str => tcx.lang_items.str_impl(),
2268+
Slice => tcx.lang_items.slice_impl(),
2269+
Array => tcx.lang_items.slice_impl(),
2270+
PrimitiveTuple => None,
2271+
PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
2272+
};
2273+
if let Some(did) = did {
2274+
if !ast_util::is_local(did) {
2275+
inline::build_impl(cx, tcx, did, ret);
2276+
}
22072277
}
22082278
}
22092279
}

src/librustdoc/core.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_resolve as resolve;
2020

2121
use syntax::{ast, ast_map, codemap, diagnostic};
2222

23-
use std::cell::RefCell;
23+
use std::cell::{RefCell, Cell};
2424
use std::collections::{HashMap, HashSet};
2525

2626
use visit_ast::RustdocVisitor;
@@ -48,6 +48,7 @@ pub struct DocContext<'tcx> {
4848
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
4949
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
5050
pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
51+
pub deref_trait_did: Cell<Option<ast::DefId>>,
5152
}
5253

5354
impl<'tcx> DocContext<'tcx> {
@@ -77,6 +78,7 @@ pub struct CrateAnalysis {
7778
pub external_paths: ExternalPaths,
7879
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
7980
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
81+
pub deref_trait_did: Option<ast::DefId>,
8082
}
8183

8284
pub type Externs = HashMap<String, Vec<String>>;
@@ -147,15 +149,17 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
147149
external_paths: RefCell::new(Some(HashMap::new())),
148150
inlined: RefCell::new(Some(HashSet::new())),
149151
populated_crate_impls: RefCell::new(HashSet::new()),
152+
deref_trait_did: Cell::new(None),
150153
};
151154
debug!("crate: {:?}", ctxt.krate);
152155

153-
let analysis = CrateAnalysis {
156+
let mut analysis = CrateAnalysis {
154157
exported_items: exported_items,
155158
public_items: public_items,
156159
external_paths: RefCell::new(None),
157160
external_typarams: RefCell::new(None),
158161
inlined: RefCell::new(None),
162+
deref_trait_did: None,
159163
};
160164

161165
let krate = {
@@ -170,5 +174,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
170174
*analysis.external_typarams.borrow_mut() = map;
171175
let map = ctxt.inlined.borrow_mut().take();
172176
*analysis.inlined.borrow_mut() = map;
177+
analysis.deref_trait_did = ctxt.deref_trait_did.get();
173178
(krate, analysis)
174179
}

0 commit comments

Comments
 (0)