提交 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>)> { ...@@ -433,7 +433,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
/// Used when rendering a `ResolvedPath` structure. This invokes the `path` /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local 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, 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 last = path.segments.last().unwrap();
let rel_root = match &*path.segments[0].name { let rel_root = match &*path.segments[0].name {
"self" => Some("./".to_string()), "self" => Some("./".to_string()),
...@@ -467,7 +467,17 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, ...@@ -467,7 +467,17 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
if w.alternate() { if w.alternate() {
write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?; write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
} else { } 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(()) Ok(())
} }
...@@ -551,194 +561,198 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ...@@ -551,194 +561,198 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
} }
} }
impl fmt::Display for clean::Type { fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, full_path: bool) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *t {
match *self { clean::Generic(ref name) => {
clean::Generic(ref name) => { f.write_str(name)
f.write_str(name) }
} clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => { // Paths like T::Output and Self::Output should be rendered with all segments
// Paths like T::Output and Self::Output should be rendered with all segments resolved_path(f, did, path, is_generic, full_path)?;
resolved_path(f, did, path, is_generic)?; tybounds(f, typarams)
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::Tuple(ref typs) => {
clean::BareFunction(ref decl) => { match &typs[..] {
if f.alternate() { &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
write!(f, "{}{}fn{:#}{:#}", &[ref one] => {
UnsafetySpace(decl.unsafety), primitive_link(f, PrimitiveType::Tuple, "(")?;
AbiSpace(decl.abi), //carry f.alternate() into this display w/o branching manually
decl.generics, fmt::Display::fmt(one, f)?;
decl.decl) primitive_link(f, PrimitiveType::Tuple, ",)")
} else {
write!(f, "{}{}fn{}{}",
UnsafetySpace(decl.unsafety),
AbiSpace(decl.abi),
decl.generics,
decl.decl)
} }
} many => {
clean::Tuple(ref typs) => { primitive_link(f, PrimitiveType::Tuple, "(")?;
match &typs[..] { fmt::Display::fmt(&CommaSep(&many), f)?;
&[] => primitive_link(f, PrimitiveType::Tuple, "()"), 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, ")")
}
} }
} }
clean::Vector(ref t) => { }
primitive_link(f, PrimitiveType::Slice, &format!("["))?; clean::Vector(ref t) => {
fmt::Display::fmt(t, f)?; primitive_link(f, PrimitiveType::Slice, &format!("["))?;
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, "[")?; clean::FixedVector(ref t, ref s) => {
fmt::Display::fmt(t, f)?; primitive_link(f, PrimitiveType::Array, "[")?;
if f.alternate() { fmt::Display::fmt(t, f)?;
primitive_link(f, PrimitiveType::Array, if f.alternate() {
&format!("; {}]", s)) primitive_link(f, PrimitiveType::Array,
} else { &format!("; {}]", s))
primitive_link(f, PrimitiveType::Array, } else {
&format!("; {}]", Escape(s))) primitive_link(f, PrimitiveType::Array,
} &format!("; {}]", Escape(s)))
} }
clean::Never => f.write_str("!"), }
clean::RawPointer(m, ref t) => { clean::Never => f.write_str("!"),
match **t { clean::RawPointer(m, ref t) => {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { match **t {
if f.alternate() { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
primitive_link(f, clean::PrimitiveType::RawPointer, if f.alternate() {
&format!("*{}{:#}", RawMutableSpace(m), t))
} else {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}{}", RawMutableSpace(m), t))
}
}
_ => {
primitive_link(f, clean::PrimitiveType::RawPointer, primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}", RawMutableSpace(m)))?; &format!("*{}{:#}", RawMutableSpace(m), t))
fmt::Display::fmt(t, f) } 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 { clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
Some(ref l) => format!("{} ", *l), let lt = match *l {
_ => "".to_string(), Some(ref l) => format!("{} ", *l),
}; _ => "".to_string(),
let m = MutableSpace(mutability); };
match **ty { let m = MutableSpace(mutability);
clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T] match **ty {
match **bt { clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
clean::Generic(_) => match **bt {
if f.alternate() { clean::Generic(_) =>
primitive_link(f, PrimitiveType::Slice, if f.alternate() {
&format!("&{}{}[{:#}]", lt, m, **bt)) primitive_link(f, PrimitiveType::Slice,
} else { &format!("&{}{}[{:#}]", lt, m, **bt))
primitive_link(f, PrimitiveType::Slice, } else {
&format!("&amp;{}{}[{}]", lt, m, **bt)) primitive_link(f, PrimitiveType::Slice,
}, &format!("&amp;{}{}[{}]", lt, m, **bt))
_ => { },
if f.alternate() { _ => {
primitive_link(f, PrimitiveType::Slice, if f.alternate() {
&format!("&{}{}[", lt, m))?; primitive_link(f, PrimitiveType::Slice,
write!(f, "{:#}", **bt)?; &format!("&{}{}[", lt, m))?;
} else { write!(f, "{:#}", **bt)?;
primitive_link(f, PrimitiveType::Slice, } else {
&format!("&amp;{}{}[", lt, m))?; primitive_link(f, PrimitiveType::Slice,
write!(f, "{}", **bt)?; &format!("&amp;{}{}[", lt, m))?;
} write!(f, "{}", **bt)?;
primitive_link(f, PrimitiveType::Slice, "]")
} }
} primitive_link(f, PrimitiveType::Slice, "]")
}
_ => {
if f.alternate() {
write!(f, "&{}{}{:#}", lt, m, **ty)
} else {
write!(f, "&amp;{}{}{}", lt, m, **ty)
} }
} }
} }
} _ => {
clean::PolyTraitRef(ref bounds) => {
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
write!(f, " + ")?;
}
if f.alternate() { if f.alternate() {
write!(f, "{:#}", *bound)?; write!(f, "&{}{}{:#}", lt, m, **ty)
} else { } else {
write!(f, "{}", *bound)?; write!(f, "&amp;{}{}{}", lt, m, **ty)
} }
} }
Ok(())
} }
clean::ImplTrait(ref bounds) => { }
write!(f, "impl ")?; clean::PolyTraitRef(ref bounds) => {
for (i, bound) in bounds.iter().enumerate() { for (i, bound) in bounds.iter().enumerate() {
if i != 0 { if i != 0 {
write!(f, " + ")?; write!(f, " + ")?;
}
if f.alternate() {
write!(f, "{:#}", *bound)?;
} else {
write!(f, "{}", *bound)?;
}
} }
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() { if f.alternate() {
write!(f, "{:#}::", self_type)?; write!(f, "{:#}", *bound)?;
} else { } 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() { if f.alternate() {
write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name) write!(f, "{:#}", *bound)?;
} else { } else {
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name) write!(f, "{}", *bound)?;
} }
} }
clean::Unique(..) => { Ok(())
panic!("should have been cleaned") }
// 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(); let mut plain = String::new();
if f.alternate() { if f.alternate() {
...@@ -759,7 +773,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R ...@@ -759,7 +773,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
plain.push_str(&format!("{:#}", ty)); plain.push_str(&format!("{:#}", ty));
} else { } else {
match *ty { 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(); let last = path.segments.last().unwrap();
fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.name, f)?;
fmt::Display::fmt(&last.params, 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 ...@@ -772,7 +786,7 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R
plain.push_str(" for "); plain.push_str(" for ");
} }
fmt::Display::fmt(&i.for_, f)?; fmt_type(&i.for_, f, full)?;
plain.push_str(&format!("{:#}", i.for_)); plain.push_str(&format!("{:#}", i.for_));
fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; 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 ...@@ -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 { impl fmt::Display for clean::Impl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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. // 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 { pub fn fmt_impl_for_trait_page(i: &clean::Impl,
fmt_impl(i, f, false) f: &mut fmt::Formatter,
disambiguate: bool) -> fmt::Result {
fmt_impl(i, f, false, disambiguate)
} }
impl fmt::Display for clean::Arguments { impl fmt::Display for clean::Arguments {
...@@ -978,7 +994,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ...@@ -978,7 +994,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Display for clean::ImportSource { impl fmt::Display for clean::ImportSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.did { 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() { for (i, seg) in self.path.segments.iter().enumerate() {
if i > 0 { if i > 0 {
......
...@@ -2111,9 +2111,23 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean:: ...@@ -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'> <ul class='item-list' id='implementors-list'>
")?; ")?;
if let Some(implementors) = cache.implementors.get(&it.def_id) { if let Some(implementors) = cache.implementors.get(&it.def_id) {
for i in implementors { for k in implementors.iter() {
write!(w, "<li><code>")?; 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>")?; writeln!(w, "</code></li>")?;
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册