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:
parent
8fb31f75c9
commit
71c1b5b704
@ -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,
|
||||
did: ast::DefId) -> Vec<clean::Item> {
|
||||
pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
|
||||
did: ast::DefId) -> Vec<clean::Item> {
|
||||
ty::populate_implementations_for_type_if_necessary(tcx, did);
|
||||
let mut impls = Vec::new();
|
||||
|
||||
match tcx.inherent_impls.borrow().get(&did) {
|
||||
None => {}
|
||||
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,
|
||||
def: decoder::DefLike,
|
||||
impls: &mut Vec<Option<clean::Item>>) {
|
||||
impls: &mut Vec<clean::Item>) {
|
||||
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)) => {
|
||||
csearch::each_child_of_item(&tcx.sess.cstore,
|
||||
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,
|
||||
tcx: &ty::ctxt,
|
||||
did: ast::DefId) -> Option<clean::Item> {
|
||||
pub fn build_impl(cx: &DocContext,
|
||||
tcx: &ty::ctxt,
|
||||
did: ast::DefId,
|
||||
ret: &mut Vec<clean::Item>) {
|
||||
if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
|
||||
return None
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
let trait_attrs = load_attrs(cx, tcx, t.def_id);
|
||||
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 csearch::is_default_impl(&tcx.sess.cstore, did) {
|
||||
return Some(clean::Item {
|
||||
return ret.push(clean::Item {
|
||||
inner: clean::DefaultImplItem(clean::DefaultImpl {
|
||||
// FIXME: this should be decoded
|
||||
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 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 {
|
||||
unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded
|
||||
derived: clean::detect_derived(&attrs),
|
||||
trait_: associated_trait.clean(cx).map(|bound| {
|
||||
match bound {
|
||||
clean::TraitBound(polyt, _) => polyt.trait_,
|
||||
clean::RegionBound(..) => unreachable!(),
|
||||
}
|
||||
}),
|
||||
trait_: trait_,
|
||||
for_: ty.ty.clean(cx),
|
||||
generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
|
||||
items: trait_items,
|
||||
|
@ -128,6 +128,10 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Crate {
|
||||
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();
|
||||
cx.sess().cstore.iter_crate_data(|n, meta| {
|
||||
externs.push((n, meta.clean(cx)));
|
||||
@ -321,7 +325,7 @@ impl Item {
|
||||
attr::Unstable => "unstable".to_string(),
|
||||
attr::Stable => String::new(),
|
||||
};
|
||||
if s.deprecated_since.len() > 0 {
|
||||
if !s.deprecated_since.is_empty() {
|
||||
base.push_str(" deprecated");
|
||||
}
|
||||
base
|
||||
@ -387,7 +391,7 @@ impl Clean<Item> for doctree::Module {
|
||||
items.extend(self.statics.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.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.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")
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Impl {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
Item {
|
||||
impl Clean<Vec<Item>> for doctree::Impl {
|
||||
fn clean(&self, cx: &DocContext) -> Vec<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,
|
||||
attrs: self.attrs.clean(cx),
|
||||
source: self.whence.clean(cx),
|
||||
@ -2198,12 +2214,66 @@ impl Clean<Item> for doctree::Impl {
|
||||
inner: ImplItem(Impl {
|
||||
unsafety: self.unsafety,
|
||||
generics: self.generics.clean(cx),
|
||||
trait_: self.trait_.clean(cx),
|
||||
trait_: trait_,
|
||||
for_: self.for_.clean(cx),
|
||||
items: self.items.clean(cx),
|
||||
items: items,
|
||||
derived: detect_derived(&self.attrs),
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ use rustc_resolve as resolve;
|
||||
|
||||
use syntax::{ast, ast_map, codemap, diagnostic};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{RefCell, Cell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use visit_ast::RustdocVisitor;
|
||||
@ -48,6 +48,7 @@ pub struct DocContext<'tcx> {
|
||||
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
|
||||
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
|
||||
pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
|
||||
pub deref_trait_did: Cell<Option<ast::DefId>>,
|
||||
}
|
||||
|
||||
impl<'tcx> DocContext<'tcx> {
|
||||
@ -77,6 +78,7 @@ pub struct CrateAnalysis {
|
||||
pub external_paths: ExternalPaths,
|
||||
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
|
||||
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
|
||||
pub deref_trait_did: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
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())),
|
||||
inlined: RefCell::new(Some(HashSet::new())),
|
||||
populated_crate_impls: RefCell::new(HashSet::new()),
|
||||
deref_trait_did: Cell::new(None),
|
||||
};
|
||||
debug!("crate: {:?}", ctxt.krate);
|
||||
|
||||
let analysis = CrateAnalysis {
|
||||
let mut analysis = CrateAnalysis {
|
||||
exported_items: exported_items,
|
||||
public_items: public_items,
|
||||
external_paths: RefCell::new(None),
|
||||
external_typarams: RefCell::new(None),
|
||||
inlined: RefCell::new(None),
|
||||
deref_trait_did: None,
|
||||
};
|
||||
|
||||
let krate = {
|
||||
@ -170,5 +174,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
*analysis.external_typarams.borrow_mut() = map;
|
||||
let map = ctxt.inlined.borrow_mut().take();
|
||||
*analysis.inlined.borrow_mut() = map;
|
||||
analysis.deref_trait_did = ctxt.deref_trait_did.get();
|
||||
(krate, analysis)
|
||||
}
|
||||
|
@ -209,6 +209,7 @@ pub struct Cache {
|
||||
privmod: bool,
|
||||
remove_priv: bool,
|
||||
public_items: NodeSet,
|
||||
deref_trait_did: Option<ast::DefId>,
|
||||
|
||||
// In rare case where a structure is defined in one module but implemented
|
||||
// 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,
|
||||
orphan_methods: Vec::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| {
|
||||
a.external_typarams.borrow_mut().take().unwrap()
|
||||
}).unwrap_or(HashMap::new()),
|
||||
@ -403,8 +405,6 @@ pub fn run(mut krate: clean::Crate,
|
||||
a.inlined.borrow_mut().take().unwrap()
|
||||
}).unwrap_or(HashSet::new()),
|
||||
};
|
||||
cache.stack.push(krate.name.clone());
|
||||
krate = cache.fold_crate(krate);
|
||||
|
||||
// Cache where all our extern crates are located
|
||||
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.stack.push(krate.name.clone());
|
||||
krate = cache.fold_crate(krate);
|
||||
|
||||
// Build our search index
|
||||
let index = try!(build_index(&krate, &mut cache));
|
||||
|
||||
@ -1069,8 +1072,11 @@ impl DocFolder for Cache {
|
||||
}
|
||||
|
||||
ref t => {
|
||||
t.primitive_type().map(|p| {
|
||||
ast_util::local_def(p.to_node_id())
|
||||
t.primitive_type().and_then(|t| {
|
||||
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> {
|
||||
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)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let text = if stab.deprecated_since.len() > 0 {
|
||||
let text = if !stab.deprecated_since.is_empty() {
|
||||
let since = if show_reason {
|
||||
format!(" since {}", Escape(&stab.deprecated_since))
|
||||
} 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.
|
||||
try!(render_methods(w, it));
|
||||
try!(render_methods(w, it.def_id, MethodRender::All));
|
||||
|
||||
let cache = cache();
|
||||
try!(write!(w, "
|
||||
@ -1995,7 +2001,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
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,
|
||||
@ -2094,7 +2100,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
try!(write!(w, "</table>"));
|
||||
|
||||
}
|
||||
try!(render_methods(w, it));
|
||||
try!(render_methods(w, it.def_id, MethodRender::All));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -2183,27 +2189,61 @@ enum MethodLink {
|
||||
GotoSource(ast::DefId),
|
||||
}
|
||||
|
||||
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
|
||||
let v = match cache().impls.get(&it.def_id) {
|
||||
Some(v) => v.clone(),
|
||||
enum MethodRender<'a> {
|
||||
All,
|
||||
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(()),
|
||||
};
|
||||
let (non_trait, traits): (Vec<_>, _) = v.into_iter()
|
||||
.partition(|i| i.impl_.trait_.is_none());
|
||||
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| {
|
||||
i.impl_.trait_.is_none()
|
||||
});
|
||||
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 \
|
||||
{}<Target={}></h2>", trait_, type_));
|
||||
false
|
||||
}
|
||||
};
|
||||
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() {
|
||||
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 \
|
||||
Implementations</h2>"));
|
||||
let (derived, manual): (Vec<_>, _) = traits.into_iter()
|
||||
.partition(|i| i.impl_.derived);
|
||||
let (derived, manual): (Vec<_>, _) = traits.iter().partition(|i| {
|
||||
i.impl_.derived
|
||||
});
|
||||
for i in &manual {
|
||||
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() {
|
||||
try!(write!(w, "<h3 id='derived_implementations'>\
|
||||
@ -2211,27 +2251,52 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
|
||||
</h3>"));
|
||||
for i in &derived {
|
||||
let did = i.trait_did().unwrap();
|
||||
try!(render_impl(w, i, MethodLink::GotoSource(did)));
|
||||
try!(render_impl(w, i, MethodLink::GotoSource(did), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink)
|
||||
-> fmt::Result {
|
||||
try!(write!(w, "<h3 class='impl'><code>impl{} ",
|
||||
i.impl_.generics));
|
||||
if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity {
|
||||
try!(write!(w, "!"));
|
||||
fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
|
||||
let deref_type = impl_.impl_.trait_.as_ref().unwrap();
|
||||
let target = impl_.impl_.items.iter().filter_map(|item| {
|
||||
match item.inner {
|
||||
clean::TypedefItem(ref t) => Some(&t.type_),
|
||||
_ => 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));
|
||||
}
|
||||
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 render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
||||
render_header: bool) -> fmt::Result {
|
||||
if render_header {
|
||||
try!(write!(w, "<h3 class='impl'><code>impl{} ",
|
||||
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,
|
||||
@ -2393,7 +2458,7 @@ fn item_primitive(w: &mut fmt::Formatter,
|
||||
it: &clean::Item,
|
||||
_p: &clean::PrimitiveType) -> fmt::Result {
|
||||
try!(document(w, it));
|
||||
render_methods(w, it)
|
||||
render_methods(w, it.def_id, MethodRender::All)
|
||||
}
|
||||
|
||||
fn get_basic_keywords() -> &'static str {
|
||||
|
@ -481,9 +481,12 @@ em.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
|
||||
em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
|
||||
em.stab {
|
||||
display: inline-block;
|
||||
border-width: 2px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
padding: 5px;
|
||||
padding: 3px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 90%;
|
||||
font-style: normal;
|
||||
}
|
||||
em.stab p {
|
||||
display: inline;
|
||||
@ -492,6 +495,7 @@ em.stab p {
|
||||
.module-item .stab {
|
||||
border-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: inherit !important;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{RefCell, Cell};
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use std::dynamic_lib::DynamicLibrary;
|
||||
use std::env;
|
||||
@ -92,6 +92,7 @@ pub fn run(input: &str,
|
||||
external_typarams: RefCell::new(None),
|
||||
inlined: RefCell::new(None),
|
||||
populated_crate_impls: RefCell::new(HashSet::new()),
|
||||
deref_trait_did: Cell::new(None),
|
||||
};
|
||||
|
||||
let mut v = RustdocVisitor::new(&ctx, None);
|
||||
|
30
src/test/auxiliary/issue-19190-3.rs
Normal file
30
src/test/auxiliary/issue-19190-3.rs
Normal 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 {} }
|
||||
}
|
22
src/test/rustdoc/issue-19190-2.rs
Normal file
22
src/test/rustdoc/issue-19190-2.rs
Normal 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'
|
||||
|
35
src/test/rustdoc/issue-19190-3.rs
Normal file
35
src/test/rustdoc/issue-19190-3.rs
Normal 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 {} }
|
||||
}
|
||||
|
26
src/test/rustdoc/issue-19190.rs
Normal file
26
src/test/rustdoc/issue-19190.rs
Normal 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)'
|
Loading…
x
Reference in New Issue
Block a user