diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 28ca92f5db6f6..a48af1c162b5f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2205,8 +2205,8 @@ impl Path { } } - pub fn last_name(&self) -> String { - self.segments.last().unwrap().name.clone() + pub fn last_name(&self) -> &str { + self.segments.last().unwrap().name.as_str() } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6dc6e80dae0b8..ed7ad36cc8468 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)> { /// 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,201 @@ 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, use_absolute: 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, use_absolute)?; + 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!("&{}{}[{}]", lt, m, **bt)) - }, - _ => { - if f.alternate() { - primitive_link(f, PrimitiveType::Slice, - &format!("&{}{}[", lt, m))?; - write!(f, "{:#}", **bt)?; - } else { - primitive_link(f, PrimitiveType::Slice, - &format!("&{}{}[", 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!("&{}{}[{}]", lt, m, **bt)) + }, + _ => { + if f.alternate() { + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[", lt, m))?; + write!(f, "{:#}", **bt)?; + } else { + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[", lt, m))?; + write!(f, "{}", **bt)?; } - } - } - _ => { - if f.alternate() { - write!(f, "&{}{}{:#}", lt, m, **ty) - } else { - write!(f, "&{}{}{}", 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, "&{}{}{}", 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 `::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, "<{} as {}>::{}", self_type, trait_, name) + write!(f, "{}", *bound)?; } } - clean::Unique(..) => { - panic!("should have been cleaned") + Ok(()) + } + // It's pretty unsightly to look at `::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, use_absolute)?; + + // 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, "<{} as {}>::{}", 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, + use_absolute: bool) -> fmt::Result { let mut plain = String::new(); if f.alternate() { @@ -759,7 +776,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 +789,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, use_absolute)?; plain.push_str(&format!("{:#}", i.for_)); fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; @@ -781,13 +798,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, + use_absolute: bool) -> fmt::Result { + fmt_impl(i, f, false, use_absolute) } impl fmt::Display for clean::Arguments { @@ -978,7 +997,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 e721b66779fff..dcf7515f87531 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2111,9 +2111,25 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,