1
Fork 0

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
This commit is contained in:
Alex Crichton 2015-04-13 16:23:32 -07:00
parent 8fb31f75c9
commit 71c1b5b704
10 changed files with 333 additions and 66 deletions

View file

@ -218,15 +218,17 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn
}) })
} }
fn build_impls(cx: &DocContext, tcx: &ty::ctxt, pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
did: ast::DefId) -> Vec<clean::Item> { did: ast::DefId) -> Vec<clean::Item> {
ty::populate_implementations_for_type_if_necessary(tcx, did); ty::populate_implementations_for_type_if_necessary(tcx, did);
let mut impls = Vec::new(); let mut impls = Vec::new();
match tcx.inherent_impls.borrow().get(&did) { match tcx.inherent_impls.borrow().get(&did) {
None => {} None => {}
Some(i) => { Some(i) => {
impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) })); for &did in i.iter() {
build_impl(cx, tcx, did, &mut impls);
}
} }
} }
@ -247,9 +249,9 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
fn populate_impls(cx: &DocContext, tcx: &ty::ctxt, fn populate_impls(cx: &DocContext, tcx: &ty::ctxt,
def: decoder::DefLike, def: decoder::DefLike,
impls: &mut Vec<Option<clean::Item>>) { impls: &mut Vec<clean::Item>) {
match def { match def {
decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)), decoder::DlImpl(did) => build_impl(cx, tcx, did, impls),
decoder::DlDef(def::DefMod(did)) => { decoder::DlDef(def::DefMod(did)) => {
csearch::each_child_of_item(&tcx.sess.cstore, csearch::each_child_of_item(&tcx.sess.cstore,
did, did,
@ -262,14 +264,15 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
} }
} }
impls.into_iter().filter_map(|a| a).collect() return impls;
} }
fn build_impl(cx: &DocContext, pub fn build_impl(cx: &DocContext,
tcx: &ty::ctxt, tcx: &ty::ctxt,
did: ast::DefId) -> Option<clean::Item> { did: ast::DefId,
ret: &mut Vec<clean::Item>) {
if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) { if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
return None return
} }
let attrs = load_attrs(cx, tcx, did); let attrs = load_attrs(cx, tcx, did);
@ -278,13 +281,13 @@ fn build_impl(cx: &DocContext,
// If this is an impl for a #[doc(hidden)] trait, be sure to not inline // If this is an impl for a #[doc(hidden)] trait, be sure to not inline
let trait_attrs = load_attrs(cx, tcx, t.def_id); let trait_attrs = load_attrs(cx, tcx, t.def_id);
if trait_attrs.iter().any(|a| is_doc_hidden(a)) { if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
return None return
} }
} }
// If this is a defaulted impl, then bail out early here // If this is a defaulted impl, then bail out early here
if csearch::is_default_impl(&tcx.sess.cstore, did) { if csearch::is_default_impl(&tcx.sess.cstore, did) {
return Some(clean::Item { return ret.push(clean::Item {
inner: clean::DefaultImplItem(clean::DefaultImpl { inner: clean::DefaultImplItem(clean::DefaultImpl {
// FIXME: this should be decoded // FIXME: this should be decoded
unsafety: ast::Unsafety::Normal, unsafety: ast::Unsafety::Normal,
@ -352,19 +355,25 @@ fn build_impl(cx: &DocContext,
}) })
} }
} }
}).collect(); }).collect::<Vec<_>>();
let polarity = csearch::get_impl_polarity(tcx, did); let polarity = csearch::get_impl_polarity(tcx, did);
let ty = ty::lookup_item_type(tcx, did); let ty = ty::lookup_item_type(tcx, did);
return Some(clean::Item { let trait_ = associated_trait.clean(cx).map(|bound| {
match bound {
clean::TraitBound(polyt, _) => polyt.trait_,
clean::RegionBound(..) => unreachable!(),
}
});
if let Some(clean::ResolvedPath { did, .. }) = trait_ {
if Some(did) == cx.deref_trait_did.get() {
super::build_deref_target_impls(cx, &trait_items, ret);
}
}
ret.push(clean::Item {
inner: clean::ImplItem(clean::Impl { inner: clean::ImplItem(clean::Impl {
unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded
derived: clean::detect_derived(&attrs), derived: clean::detect_derived(&attrs),
trait_: associated_trait.clean(cx).map(|bound| { trait_: trait_,
match bound {
clean::TraitBound(polyt, _) => polyt.trait_,
clean::RegionBound(..) => unreachable!(),
}
}),
for_: ty.ty.clean(cx), for_: ty.ty.clean(cx),
generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx), generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
items: trait_items, items: trait_items,

View file

@ -128,6 +128,10 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
fn clean(&self, cx: &DocContext) -> Crate { fn clean(&self, cx: &DocContext) -> Crate {
use rustc::session::config::Input; use rustc::session::config::Input;
if let Some(t) = cx.tcx_opt() {
cx.deref_trait_did.set(t.lang_items.deref_trait());
}
let mut externs = Vec::new(); let mut externs = Vec::new();
cx.sess().cstore.iter_crate_data(|n, meta| { cx.sess().cstore.iter_crate_data(|n, meta| {
externs.push((n, meta.clean(cx))); externs.push((n, meta.clean(cx)));
@ -321,7 +325,7 @@ impl Item {
attr::Unstable => "unstable".to_string(), attr::Unstable => "unstable".to_string(),
attr::Stable => String::new(), attr::Stable => String::new(),
}; };
if s.deprecated_since.len() > 0 { if !s.deprecated_since.is_empty() {
base.push_str(" deprecated"); base.push_str(" deprecated");
} }
base base
@ -387,7 +391,7 @@ impl Clean<Item> for doctree::Module {
items.extend(self.statics.iter().map(|x| x.clean(cx))); items.extend(self.statics.iter().map(|x| x.clean(cx)));
items.extend(self.constants.iter().map(|x| x.clean(cx))); items.extend(self.constants.iter().map(|x| x.clean(cx)));
items.extend(self.traits.iter().map(|x| x.clean(cx))); items.extend(self.traits.iter().map(|x| x.clean(cx)));
items.extend(self.impls.iter().map(|x| x.clean(cx))); items.extend(self.impls.iter().flat_map(|x| x.clean(cx).into_iter()));
items.extend(self.macros.iter().map(|x| x.clean(cx))); items.extend(self.macros.iter().map(|x| x.clean(cx)));
items.extend(self.def_traits.iter().map(|x| x.clean(cx))); items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
@ -2186,9 +2190,21 @@ fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
attr::contains_name(attrs, "automatically_derived") attr::contains_name(attrs, "automatically_derived")
} }
impl Clean<Item> for doctree::Impl { impl Clean<Vec<Item>> for doctree::Impl {
fn clean(&self, cx: &DocContext) -> Item { fn clean(&self, cx: &DocContext) -> Vec<Item> {
Item { let mut ret = Vec::new();
let trait_ = self.trait_.clean(cx);
let items = self.items.clean(cx);
// If this impl block is an implementation of the Deref trait, then we
// need to try inlining the target's inherent impl blocks as well.
if let Some(ResolvedPath { did, .. }) = trait_ {
if Some(did) == cx.deref_trait_did.get() {
build_deref_target_impls(cx, &items, &mut ret);
}
}
ret.push(Item {
name: None, name: None,
attrs: self.attrs.clean(cx), attrs: self.attrs.clean(cx),
source: self.whence.clean(cx), source: self.whence.clean(cx),
@ -2198,12 +2214,66 @@ impl Clean<Item> for doctree::Impl {
inner: ImplItem(Impl { inner: ImplItem(Impl {
unsafety: self.unsafety, unsafety: self.unsafety,
generics: self.generics.clean(cx), generics: self.generics.clean(cx),
trait_: self.trait_.clean(cx), trait_: trait_,
for_: self.for_.clean(cx), for_: self.for_.clean(cx),
items: self.items.clean(cx), items: items,
derived: detect_derived(&self.attrs), derived: detect_derived(&self.attrs),
polarity: Some(self.polarity.clean(cx)), polarity: Some(self.polarity.clean(cx)),
}), }),
});
return ret;
}
}
fn build_deref_target_impls(cx: &DocContext,
items: &[Item],
ret: &mut Vec<Item>) {
let tcx = match cx.tcx_opt() {
Some(t) => t,
None => return,
};
for item in items {
let target = match item.inner {
TypedefItem(ref t) => &t.type_,
_ => continue,
};
let primitive = match *target {
ResolvedPath { did, .. } if ast_util::is_local(did) => continue,
ResolvedPath { did, .. } => {
ret.extend(inline::build_impls(cx, tcx, did));
continue
}
_ => match target.primitive_type() {
Some(prim) => prim,
None => continue,
}
};
let did = match primitive {
Isize => tcx.lang_items.isize_impl(),
I8 => tcx.lang_items.i8_impl(),
I16 => tcx.lang_items.i16_impl(),
I32 => tcx.lang_items.i32_impl(),
I64 => tcx.lang_items.i64_impl(),
Usize => tcx.lang_items.usize_impl(),
U8 => tcx.lang_items.u8_impl(),
U16 => tcx.lang_items.u16_impl(),
U32 => tcx.lang_items.u32_impl(),
U64 => tcx.lang_items.u64_impl(),
F32 => tcx.lang_items.f32_impl(),
F64 => tcx.lang_items.f64_impl(),
Char => tcx.lang_items.char_impl(),
Bool => None,
Str => tcx.lang_items.str_impl(),
Slice => tcx.lang_items.slice_impl(),
Array => tcx.lang_items.slice_impl(),
PrimitiveTuple => None,
PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
};
if let Some(did) = did {
if !ast_util::is_local(did) {
inline::build_impl(cx, tcx, did, ret);
}
} }
} }
} }

View file

@ -20,7 +20,7 @@ use rustc_resolve as resolve;
use syntax::{ast, ast_map, codemap, diagnostic}; use syntax::{ast, ast_map, codemap, diagnostic};
use std::cell::RefCell; use std::cell::{RefCell, Cell};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use visit_ast::RustdocVisitor; use visit_ast::RustdocVisitor;
@ -48,6 +48,7 @@ pub struct DocContext<'tcx> {
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>, pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
pub inlined: RefCell<Option<HashSet<ast::DefId>>>, pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>, pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
pub deref_trait_did: Cell<Option<ast::DefId>>,
} }
impl<'tcx> DocContext<'tcx> { impl<'tcx> DocContext<'tcx> {
@ -77,6 +78,7 @@ pub struct CrateAnalysis {
pub external_paths: ExternalPaths, pub external_paths: ExternalPaths,
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>, pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
pub inlined: RefCell<Option<HashSet<ast::DefId>>>, pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
pub deref_trait_did: Option<ast::DefId>,
} }
pub type Externs = HashMap<String, Vec<String>>; pub type Externs = HashMap<String, Vec<String>>;
@ -147,15 +149,17 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
external_paths: RefCell::new(Some(HashMap::new())), external_paths: RefCell::new(Some(HashMap::new())),
inlined: RefCell::new(Some(HashSet::new())), inlined: RefCell::new(Some(HashSet::new())),
populated_crate_impls: RefCell::new(HashSet::new()), populated_crate_impls: RefCell::new(HashSet::new()),
deref_trait_did: Cell::new(None),
}; };
debug!("crate: {:?}", ctxt.krate); debug!("crate: {:?}", ctxt.krate);
let analysis = CrateAnalysis { let mut analysis = CrateAnalysis {
exported_items: exported_items, exported_items: exported_items,
public_items: public_items, public_items: public_items,
external_paths: RefCell::new(None), external_paths: RefCell::new(None),
external_typarams: RefCell::new(None), external_typarams: RefCell::new(None),
inlined: RefCell::new(None), inlined: RefCell::new(None),
deref_trait_did: None,
}; };
let krate = { let krate = {
@ -170,5 +174,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
*analysis.external_typarams.borrow_mut() = map; *analysis.external_typarams.borrow_mut() = map;
let map = ctxt.inlined.borrow_mut().take(); let map = ctxt.inlined.borrow_mut().take();
*analysis.inlined.borrow_mut() = map; *analysis.inlined.borrow_mut() = map;
analysis.deref_trait_did = ctxt.deref_trait_did.get();
(krate, analysis) (krate, analysis)
} }

View file

@ -209,6 +209,7 @@ pub struct Cache {
privmod: bool, privmod: bool,
remove_priv: bool, remove_priv: bool,
public_items: NodeSet, public_items: NodeSet,
deref_trait_did: Option<ast::DefId>,
// In rare case where a structure is defined in one module but implemented // In rare case where a structure is defined in one module but implemented
// in another, if the implementing module is parsed before defining module, // in another, if the implementing module is parsed before defining module,
@ -396,6 +397,7 @@ pub fn run(mut krate: clean::Crate,
public_items: public_items, public_items: public_items,
orphan_methods: Vec::new(), orphan_methods: Vec::new(),
traits: mem::replace(&mut krate.external_traits, HashMap::new()), traits: mem::replace(&mut krate.external_traits, HashMap::new()),
deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
typarams: analysis.as_ref().map(|a| { typarams: analysis.as_ref().map(|a| {
a.external_typarams.borrow_mut().take().unwrap() a.external_typarams.borrow_mut().take().unwrap()
}).unwrap_or(HashMap::new()), }).unwrap_or(HashMap::new()),
@ -403,8 +405,6 @@ pub fn run(mut krate: clean::Crate,
a.inlined.borrow_mut().take().unwrap() a.inlined.borrow_mut().take().unwrap()
}).unwrap_or(HashSet::new()), }).unwrap_or(HashSet::new()),
}; };
cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate);
// Cache where all our extern crates are located // Cache where all our extern crates are located
for &(n, ref e) in &krate.externs { for &(n, ref e) in &krate.externs {
@ -427,6 +427,9 @@ pub fn run(mut krate: clean::Crate,
cache.primitive_locations.insert(prim, ast::LOCAL_CRATE); cache.primitive_locations.insert(prim, ast::LOCAL_CRATE);
} }
cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate);
// Build our search index // Build our search index
let index = try!(build_index(&krate, &mut cache)); let index = try!(build_index(&krate, &mut cache));
@ -1069,8 +1072,11 @@ impl DocFolder for Cache {
} }
ref t => { ref t => {
t.primitive_type().map(|p| { t.primitive_type().and_then(|t| {
ast_util::local_def(p.to_node_id()) self.primitive_locations.get(&t).map(|n| {
let id = t.to_node_id();
ast::DefId { krate: *n, node: id }
})
}) })
} }
}; };
@ -1684,12 +1690,12 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
fn short_stability(item: &clean::Item, show_reason: bool) -> Option<String> { fn short_stability(item: &clean::Item, show_reason: bool) -> Option<String> {
item.stability.as_ref().and_then(|stab| { item.stability.as_ref().and_then(|stab| {
let reason = if show_reason && stab.reason.len() > 0 { let reason = if show_reason && !stab.reason.is_empty() {
format!(": {}", stab.reason) format!(": {}", stab.reason)
} else { } else {
String::new() String::new()
}; };
let text = if stab.deprecated_since.len() > 0 { let text = if !stab.deprecated_since.is_empty() {
let since = if show_reason { let since = if show_reason {
format!(" since {}", Escape(&stab.deprecated_since)) format!(" since {}", Escape(&stab.deprecated_since))
} else { } else {
@ -1865,7 +1871,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
} }
// If there are methods directly on this trait object, render them here. // If there are methods directly on this trait object, render them here.
try!(render_methods(w, it)); try!(render_methods(w, it.def_id, MethodRender::All));
let cache = cache(); let cache = cache();
try!(write!(w, " try!(write!(w, "
@ -1995,7 +2001,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
try!(write!(w, "</table>")); try!(write!(w, "</table>"));
} }
} }
render_methods(w, it) render_methods(w, it.def_id, MethodRender::All)
} }
fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
@ -2094,7 +2100,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
try!(write!(w, "</table>")); try!(write!(w, "</table>"));
} }
try!(render_methods(w, it)); try!(render_methods(w, it.def_id, MethodRender::All));
Ok(()) Ok(())
} }
@ -2183,27 +2189,61 @@ enum MethodLink {
GotoSource(ast::DefId), GotoSource(ast::DefId),
} }
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { enum MethodRender<'a> {
let v = match cache().impls.get(&it.def_id) { All,
Some(v) => v.clone(), DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
}
fn render_methods(w: &mut fmt::Formatter,
it: ast::DefId,
what: MethodRender) -> fmt::Result {
let c = cache();
let v = match c.impls.get(&it) {
Some(v) => v,
None => return Ok(()), None => return Ok(()),
}; };
let (non_trait, traits): (Vec<_>, _) = v.into_iter() let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| {
.partition(|i| i.impl_.trait_.is_none()); i.impl_.trait_.is_none()
});
if !non_trait.is_empty() { if !non_trait.is_empty() {
try!(write!(w, "<h2 id='methods'>Methods</h2>")); let render_header = match what {
MethodRender::All => {
try!(write!(w, "<h2 id='methods'>Methods</h2>"));
true
}
MethodRender::DerefFor { trait_, type_ } => {
try!(write!(w, "<h2 id='deref-methods'>Methods from \
{}&lt;Target={}&gt;</h2>", trait_, type_));
false
}
};
for i in &non_trait { for i in &non_trait {
try!(render_impl(w, i, MethodLink::Anchor)); try!(render_impl(w, i, MethodLink::Anchor, render_header));
} }
} }
if let MethodRender::DerefFor { .. } = what {
return Ok(())
}
if !traits.is_empty() { if !traits.is_empty() {
let deref_impl = traits.iter().find(|t| {
match *t.impl_.trait_.as_ref().unwrap() {
clean::ResolvedPath { did, .. } => {
Some(did) == c.deref_trait_did
}
_ => false
}
});
if let Some(impl_) = deref_impl {
try!(render_deref_methods(w, impl_));
}
try!(write!(w, "<h2 id='implementations'>Trait \ try!(write!(w, "<h2 id='implementations'>Trait \
Implementations</h2>")); Implementations</h2>"));
let (derived, manual): (Vec<_>, _) = traits.into_iter() let (derived, manual): (Vec<_>, _) = traits.iter().partition(|i| {
.partition(|i| i.impl_.derived); i.impl_.derived
});
for i in &manual { for i in &manual {
let did = i.trait_did().unwrap(); let did = i.trait_did().unwrap();
try!(render_impl(w, i, MethodLink::GotoSource(did))); try!(render_impl(w, i, MethodLink::GotoSource(did), true));
} }
if !derived.is_empty() { if !derived.is_empty() {
try!(write!(w, "<h3 id='derived_implementations'>\ try!(write!(w, "<h3 id='derived_implementations'>\
@ -2211,27 +2251,52 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
</h3>")); </h3>"));
for i in &derived { for i in &derived {
let did = i.trait_did().unwrap(); let did = i.trait_did().unwrap();
try!(render_impl(w, i, MethodLink::GotoSource(did))); try!(render_impl(w, i, MethodLink::GotoSource(did), true));
} }
} }
} }
Ok(()) Ok(())
} }
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink) fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
-> fmt::Result { let deref_type = impl_.impl_.trait_.as_ref().unwrap();
try!(write!(w, "<h3 class='impl'><code>impl{} ", let target = impl_.impl_.items.iter().filter_map(|item| {
i.impl_.generics)); match item.inner {
if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity { clean::TypedefItem(ref t) => Some(&t.type_),
try!(write!(w, "!")); _ => None,
}
}).next().unwrap();
let what = MethodRender::DerefFor { trait_: deref_type, type_: target };
match *target {
clean::ResolvedPath { did, .. } => render_methods(w, did, what),
_ => {
if let Some(prim) = target.primitive_type() {
if let Some(c) = cache().primitive_locations.get(&prim) {
let did = ast::DefId { krate: *c, node: prim.to_node_id() };
try!(render_methods(w, did, what));
}
}
Ok(())
}
} }
if let Some(ref ty) = i.impl_.trait_ { }
try!(write!(w, "{} for ", *ty));
} fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
try!(write!(w, "{}{}</code></h3>", i.impl_.for_, render_header: bool) -> fmt::Result {
WhereClause(&i.impl_.generics))); if render_header {
if let Some(ref dox) = i.dox { try!(write!(w, "<h3 class='impl'><code>impl{} ",
try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox))); i.impl_.generics));
if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity {
try!(write!(w, "!"));
}
if let Some(ref ty) = i.impl_.trait_ {
try!(write!(w, "{} for ", *ty));
}
try!(write!(w, "{}{}</code></h3>", i.impl_.for_,
WhereClause(&i.impl_.generics)));
if let Some(ref dox) = i.dox {
try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
}
} }
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
@ -2393,7 +2458,7 @@ fn item_primitive(w: &mut fmt::Formatter,
it: &clean::Item, it: &clean::Item,
_p: &clean::PrimitiveType) -> fmt::Result { _p: &clean::PrimitiveType) -> fmt::Result {
try!(document(w, it)); try!(document(w, it));
render_methods(w, it) render_methods(w, it.def_id, MethodRender::All)
} }
fn get_basic_keywords() -> &'static str { fn get_basic_keywords() -> &'static str {

View file

@ -481,9 +481,12 @@ em.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; } em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
em.stab { em.stab {
display: inline-block; display: inline-block;
border-width: 2px; border-width: 1px;
border-style: solid; border-style: solid;
padding: 5px; padding: 3px;
margin-bottom: 5px;
font-size: 90%;
font-style: normal;
} }
em.stab p { em.stab p {
display: inline; display: inline;
@ -492,6 +495,7 @@ em.stab p {
.module-item .stab { .module-item .stab {
border-width: 0; border-width: 0;
padding: 0; padding: 0;
margin: 0;
background: inherit !important; background: inherit !important;
} }

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::cell::RefCell; use std::cell::{RefCell, Cell};
use std::collections::{HashSet, HashMap}; use std::collections::{HashSet, HashMap};
use std::dynamic_lib::DynamicLibrary; use std::dynamic_lib::DynamicLibrary;
use std::env; use std::env;
@ -92,6 +92,7 @@ pub fn run(input: &str,
external_typarams: RefCell::new(None), external_typarams: RefCell::new(None),
inlined: RefCell::new(None), inlined: RefCell::new(None),
populated_crate_impls: RefCell::new(HashSet::new()), populated_crate_impls: RefCell::new(HashSet::new()),
deref_trait_did: Cell::new(None),
}; };
let mut v = RustdocVisitor::new(&ctx, None); let mut v = RustdocVisitor::new(&ctx, None);

View file

@ -0,0 +1,30 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::Deref;
pub struct Foo;
impl Deref for Foo {
type Target = i32;
fn deref(&self) -> &i32 { loop {} }
}
pub struct Bar;
pub struct Baz;
impl Baz {
pub fn baz(&self) {}
}
impl Deref for Bar {
type Target = Baz;
fn deref(&self) -> &Baz { loop {} }
}

View file

@ -0,0 +1,22 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::Deref;
pub struct Bar;
impl Deref for Bar {
type Target = i32;
fn deref(&self) -> &i32 { loop {} }
}
// @has issue_19190_2/struct.Bar.html
// @has - '//*[@id="method.count_ones"]' 'fn count_ones(self) -> u32'

View file

@ -0,0 +1,35 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:issue-19190-3.rs
// ignore-android
extern crate issue_19190_3;
use std::ops::Deref;
use issue_19190_3::Baz;
// @has issue_19190_3/struct.Foo.html
// @has - '//*[@id="method.count_ones"]' 'fn count_ones(self) -> u32'
pub use issue_19190_3::Foo;
// @has issue_19190_3/struct.Bar.html
// @has - '//*[@id="method.baz"]' 'fn baz(&self)'
pub use issue_19190_3::Bar;
// @has issue_19190_3/struct.MyBar.html
// @has - '//*[@id="method.baz"]' 'fn baz(&self)'
pub struct MyBar;
impl Deref for MyBar {
type Target = Baz;
fn deref(&self) -> &Baz { loop {} }
}

View file

@ -0,0 +1,26 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::Deref;
pub struct Foo;
pub struct Bar;
impl Foo {
pub fn foo(&self) {}
}
impl Deref for Bar {
type Target = Foo;
fn deref(&self) -> &Foo { loop {} }
}
// @has issue_19190/struct.Bar.html
// @has - '//*[@id="method.foo"]' 'fn foo(&self)'