about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2016-12-15 23:13:00 -0800
committerEsteban Küber <esteban@kuber.com.ar>2016-12-15 23:13:00 -0800
commit2841bf3bc79bb866980c5aea55a96a3d1cdea2f6 (patch)
treeaa830cd0cb522bd43a2aae0feea5ea7ade2f53ab
parent6483bdd860fd89fc68846d4cc94c7ae3307a84c1 (diff)
downloadrust-2841bf3bc79bb866980c5aea55a96a3d1cdea2f6.tar.gz
rust-2841bf3bc79bb866980c5aea55a96a3d1cdea2f6.zip
Rustdoc: disambiguate Implementors when the type name is not unique
-rw-r--r--src/librustdoc/html/format.rs344
-rw-r--r--src/librustdoc/html/render.rs18
2 files changed, 196 insertions, 166 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6dc6e80dae0..6808752b1fe 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -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 @@ impl<'a> fmt::Display for HRef<'a> {
     }
 }
 
-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 @@ impl fmt::Display for clean::Import {
 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 {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index e721b66779f..c7a25814553 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2111,9 +2111,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         <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>")?;
         }
     }