1
Fork 0

Rustdoc: disambiguate Implementors when the type name is not unique

This commit is contained in:
Esteban Küber 2016-12-15 23:13:00 -08:00
parent 6483bdd860
commit 2841bf3bc7
2 changed files with 201 additions and 171 deletions

View file

@ -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,
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,15 +561,14 @@ impl<'a> fmt::Display for HRef<'a> {
} }
} }
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)?; resolved_path(f, did, path, is_generic, full_path)?;
tybounds(f, typarams) tybounds(f, typarams)
} }
clean::Infer => write!(f, "_"), clean::Infer => write!(f, "_"),
@ -718,7 +727,7 @@ impl fmt::Display for clean::Type {
write!(f, "{}::", self_type)?; write!(f, "{}::", self_type)?;
} }
let path = clean::Path::singleton(name.clone()); let path = clean::Path::singleton(name.clone());
resolved_path(f, did, &path, false)?; resolved_path(f, did, &path, true, full_path)?;
// FIXME: `typarams` are not rendered, and this seems bad? // FIXME: `typarams` are not rendered, and this seems bad?
drop(typarams); drop(typarams);
@ -736,9 +745,14 @@ impl fmt::Display for clean::Type {
} }
} }
} }
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() {
@ -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
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 @@ impl fmt::Display for clean::Import {
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 {

View file

@ -2111,9 +2111,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
<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>")?;
} }
} }