提交 2841bf3b 编写于 作者: E Esteban Küber

Rustdoc: disambiguate Implementors when the type name is not unique

上级 6483bdd8
......@@ -433,7 +433,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path.
fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
print_all: bool) -> fmt::Result {
print_all: bool, use_absolute: bool) -> fmt::Result {
let last = path.segments.last().unwrap();
let rel_root = match &*path.segments[0].name {
"self" => Some("./".to_string()),
......@@ -467,7 +467,17 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
if w.alternate() {
write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
} else {
write!(w, "{}{}", HRef::new(did, &last.name), last.params)?;
let path = if use_absolute {
match href(did) {
Some((_, _, fqp)) => format!("{}::{}",
fqp[..fqp.len()-1].join("::"),
HRef::new(did, fqp.last().unwrap())),
None => format!("{}", HRef::new(did, &last.name)),
}
} else {
format!("{}", HRef::new(did, &last.name))
};
write!(w, "{}{}", path, last.params)?;
}
Ok(())
}
......@@ -551,194 +561,198 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
impl fmt::Display for clean::Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
clean::Generic(ref name) => {
f.write_str(name)
}
clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
// Paths like T::Output and Self::Output should be rendered with all segments
resolved_path(f, did, path, is_generic)?;
tybounds(f, typarams)
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, full_path: bool) -> fmt::Result {
match *t {
clean::Generic(ref name) => {
f.write_str(name)
}
clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
// Paths like T::Output and Self::Output should be rendered with all segments
resolved_path(f, did, path, is_generic, full_path)?;
tybounds(f, typarams)
}
clean::Infer => write!(f, "_"),
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
clean::BareFunction(ref decl) => {
if f.alternate() {
write!(f, "{}{}fn{:#}{:#}",
UnsafetySpace(decl.unsafety),
AbiSpace(decl.abi),
decl.generics,
decl.decl)
} else {
write!(f, "{}{}fn{}{}",
UnsafetySpace(decl.unsafety),
AbiSpace(decl.abi),
decl.generics,
decl.decl)
}
clean::Infer => write!(f, "_"),
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
clean::BareFunction(ref decl) => {
if f.alternate() {
write!(f, "{}{}fn{:#}{:#}",
UnsafetySpace(decl.unsafety),
AbiSpace(decl.abi),
decl.generics,
decl.decl)
} else {
write!(f, "{}{}fn{}{}",
UnsafetySpace(decl.unsafety),
AbiSpace(decl.abi),
decl.generics,
decl.decl)
}
clean::Tuple(ref typs) => {
match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Tuple, "()"),
&[ref one] => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
//carry f.alternate() into this display w/o branching manually
fmt::Display::fmt(one, f)?;
primitive_link(f, PrimitiveType::Tuple, ",)")
}
}
clean::Tuple(ref typs) => {
match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Tuple, "()"),
&[ref one] => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
//carry f.alternate() into this display w/o branching manually
fmt::Display::fmt(one, f)?;
primitive_link(f, PrimitiveType::Tuple, ",)")
}
many => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
fmt::Display::fmt(&CommaSep(&many), f)?;
primitive_link(f, PrimitiveType::Tuple, ")")
}
many => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
fmt::Display::fmt(&CommaSep(&many), f)?;
primitive_link(f, PrimitiveType::Tuple, ")")
}
}
clean::Vector(ref t) => {
primitive_link(f, PrimitiveType::Slice, &format!("["))?;
fmt::Display::fmt(t, f)?;
primitive_link(f, PrimitiveType::Slice, &format!("]"))
}
clean::FixedVector(ref t, ref s) => {
primitive_link(f, PrimitiveType::Array, "[")?;
fmt::Display::fmt(t, f)?;
if f.alternate() {
primitive_link(f, PrimitiveType::Array,
&format!("; {}]", s))
} else {
primitive_link(f, PrimitiveType::Array,
&format!("; {}]", Escape(s)))
}
}
clean::Vector(ref t) => {
primitive_link(f, PrimitiveType::Slice, &format!("["))?;
fmt::Display::fmt(t, f)?;
primitive_link(f, PrimitiveType::Slice, &format!("]"))
}
clean::FixedVector(ref t, ref s) => {
primitive_link(f, PrimitiveType::Array, "[")?;
fmt::Display::fmt(t, f)?;
if f.alternate() {
primitive_link(f, PrimitiveType::Array,
&format!("; {}]", s))
} else {
primitive_link(f, PrimitiveType::Array,
&format!("; {}]", Escape(s)))
}
clean::Never => f.write_str("!"),
clean::RawPointer(m, ref t) => {
match **t {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
if f.alternate() {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}{:#}", RawMutableSpace(m), t))
} else {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}{}", RawMutableSpace(m), t))
}
}
_ => {
}
clean::Never => f.write_str("!"),
clean::RawPointer(m, ref t) => {
match **t {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
if f.alternate() {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}", RawMutableSpace(m)))?;
fmt::Display::fmt(t, f)
&format!("*{}{:#}", RawMutableSpace(m), t))
} else {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}{}", RawMutableSpace(m), t))
}
}
_ => {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}", RawMutableSpace(m)))?;
fmt::Display::fmt(t, f)
}
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
Some(ref l) => format!("{} ", *l),
_ => "".to_string(),
};
let m = MutableSpace(mutability);
match **ty {
clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
match **bt {
clean::Generic(_) =>
if f.alternate() {
primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[{:#}]", lt, m, **bt))
} else {
primitive_link(f, PrimitiveType::Slice,
&format!("&amp;{}{}[{}]", lt, m, **bt))
},
_ => {
if f.alternate() {
primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[", lt, m))?;
write!(f, "{:#}", **bt)?;
} else {
primitive_link(f, PrimitiveType::Slice,
&format!("&amp;{}{}[", lt, m))?;
write!(f, "{}", **bt)?;
}
primitive_link(f, PrimitiveType::Slice, "]")
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
Some(ref l) => format!("{} ", *l),
_ => "".to_string(),
};
let m = MutableSpace(mutability);
match **ty {
clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
match **bt {
clean::Generic(_) =>
if f.alternate() {
primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[{:#}]", lt, m, **bt))
} else {
primitive_link(f, PrimitiveType::Slice,
&format!("&amp;{}{}[{}]", lt, m, **bt))
},
_ => {
if f.alternate() {
primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[", lt, m))?;
write!(f, "{:#}", **bt)?;
} else {
primitive_link(f, PrimitiveType::Slice,
&format!("&amp;{}{}[", lt, m))?;
write!(f, "{}", **bt)?;
}
}
}
_ => {
if f.alternate() {
write!(f, "&{}{}{:#}", lt, m, **ty)
} else {
write!(f, "&amp;{}{}{}", lt, m, **ty)
primitive_link(f, PrimitiveType::Slice, "]")
}
}
}
}
clean::PolyTraitRef(ref bounds) => {
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
write!(f, " + ")?;
}
_ => {
if f.alternate() {
write!(f, "{:#}", *bound)?;
write!(f, "&{}{}{:#}", lt, m, **ty)
} else {
write!(f, "{}", *bound)?;
write!(f, "&amp;{}{}{}", lt, m, **ty)
}
}
Ok(())
}
clean::ImplTrait(ref bounds) => {
write!(f, "impl ")?;
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
write!(f, " + ")?;
}
if f.alternate() {
write!(f, "{:#}", *bound)?;
} else {
write!(f, "{}", *bound)?;
}
}
clean::PolyTraitRef(ref bounds) => {
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
write!(f, " + ")?;
}
Ok(())
}
// It's pretty unsightly to look at `<A as B>::C` in output, and
// we've got hyperlinking on our side, so try to avoid longer
// notation as much as possible by making `C` a hyperlink to trait
// `B` to disambiguate.
//
// FIXME: this is still a lossy conversion and there should probably
// be a better way of representing this in general? Most of
// the ugliness comes from inlining across crates where
// everything comes in as a fully resolved QPath (hard to
// look at).
clean::QPath {
ref name,
ref self_type,
trait_: box clean::ResolvedPath { did, ref typarams, .. },
} => {
if f.alternate() {
write!(f, "{:#}::", self_type)?;
write!(f, "{:#}", *bound)?;
} else {
write!(f, "{}::", self_type)?;
write!(f, "{}", *bound)?;
}
let path = clean::Path::singleton(name.clone());
resolved_path(f, did, &path, false)?;
// FIXME: `typarams` are not rendered, and this seems bad?
drop(typarams);
Ok(())
}
clean::QPath { ref name, ref self_type, ref trait_ } => {
Ok(())
}
clean::ImplTrait(ref bounds) => {
write!(f, "impl ")?;
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
write!(f, " + ")?;
}
if f.alternate() {
write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
write!(f, "{:#}", *bound)?;
} else {
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
write!(f, "{}", *bound)?;
}
}
clean::Unique(..) => {
panic!("should have been cleaned")
Ok(())
}
// It's pretty unsightly to look at `<A as B>::C` in output, and
// we've got hyperlinking on our side, so try to avoid longer
// notation as much as possible by making `C` a hyperlink to trait
// `B` to disambiguate.
//
// FIXME: this is still a lossy conversion and there should probably
// be a better way of representing this in general? Most of
// the ugliness comes from inlining across crates where
// everything comes in as a fully resolved QPath (hard to
// look at).
clean::QPath {
ref name,
ref self_type,
trait_: box clean::ResolvedPath { did, ref typarams, .. },
} => {
if f.alternate() {
write!(f, "{:#}::", self_type)?;
} else {
write!(f, "{}::", self_type)?;
}
let path = clean::Path::singleton(name.clone());
resolved_path(f, did, &path, true, full_path)?;
// FIXME: `typarams` are not rendered, and this seems bad?
drop(typarams);
Ok(())
}
clean::QPath { ref name, ref self_type, ref trait_ } => {
if f.alternate() {
write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
} else {
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
}
}
clean::Unique(..) => {
panic!("should have been cleaned")
}
}
}
impl fmt::Display for clean::Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_type(self, f, false)
}
}
fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result {
fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool, full: bool) -> fmt::Result {
let mut plain = String::new();
if f.alternate() {
......@@ -759,7 +773,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
plain.push_str(&format!("{:#}", ty));
} else {
match *ty {
clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => {
clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
let last = path.segments.last().unwrap();
fmt::Display::fmt(&last.name, f)?;
fmt::Display::fmt(&last.params, f)?;
......@@ -772,7 +786,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
plain.push_str(" for ");
}
fmt::Display::fmt(&i.for_, f)?;
fmt_type(&i.for_, f, full)?;
plain.push_str(&format!("{:#}", i.for_));
fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;
......@@ -781,13 +795,15 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
impl fmt::Display for clean::Impl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_impl(self, f, true)
fmt_impl(self, f, true, false)
}
}
// The difference from above is that trait is not hyperlinked.
pub fn fmt_impl_for_trait_page(i: &clean::Impl, f: &mut fmt::Formatter) -> fmt::Result {
fmt_impl(i, f, false)
pub fn fmt_impl_for_trait_page(i: &clean::Impl,
f: &mut fmt::Formatter,
disambiguate: bool) -> fmt::Result {
fmt_impl(i, f, false, disambiguate)
}
impl fmt::Display for clean::Arguments {
......@@ -978,7 +994,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Display for clean::ImportSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.did {
Some(did) => resolved_path(f, did, &self.path, true),
Some(did) => resolved_path(f, did, &self.path, true, false),
_ => {
for (i, seg) in self.path.segments.iter().enumerate() {
if i > 0 {
......
......@@ -2111,9 +2111,23 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
<ul class='item-list' id='implementors-list'>
")?;
if let Some(implementors) = cache.implementors.get(&it.def_id) {
for i in implementors {
for k in implementors.iter() {
write!(w, "<li><code>")?;
fmt_impl_for_trait_page(&i.impl_, w)?;
// If there's already another implementor that has the same abbridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let mut dissambiguate = false;
for l in implementors.iter() {
match (k.impl_.for_.clone(), l.impl_.for_.clone()) {
(clean::Type::ResolvedPath {path: path_a, ..},
clean::Type::ResolvedPath {path: path_b, ..}) => {
if k.def_id != l.def_id && path_a.last_name() == path_b.last_name() {
dissambiguate = true;
}
}
_ => (),
}
}
fmt_impl_for_trait_page(&k.impl_, w, dissambiguate)?;
writeln!(w, "</code></li>")?;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册