diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dbd1106b6a138..34ddd5726d385 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2568,8 +2568,18 @@ fn resolve_type(cx: &DocContext, debug!("resolve_type({:?},{:?})", path, id); let tcx = match cx.tcx_opt() { Some(tcx) => tcx, - // If we're extracting tests, this return value doesn't matter. - None => return Primitive(Bool), + // If we're extracting tests, this return value's accuracy is not + // important, all we want is a string representation to help people + // figure out what doctests are failing. + None => { + let did = DefId::local(DefIndex::from_u32(0)); + return ResolvedPath { + path: path, + typarams: None, + did: did, + is_generic: false + }; + } }; let def = match tcx.def_map.borrow().get(&id) { Some(k) => k.full_def(), diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index cbaff95dfddd7..1ea30a8763e40 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -422,22 +422,59 @@ impl Collector { impl DocFolder for Collector { fn fold_item(&mut self, item: clean::Item) -> Option { - let pushed = match item.name { - Some(ref name) if name.is_empty() => false, - Some(ref name) => { self.names.push(name.to_string()); true } - None => false + let current_name = match item.name { + Some(ref name) if !name.is_empty() => Some(name.clone()), + _ => typename_if_impl(&item) }; - match item.doc_value() { - Some(doc) => { - self.cnt = 0; - markdown::find_testable_code(doc, &mut *self); - } - None => {} + + let pushed = if let Some(name) = current_name { + self.names.push(name); + true + } else { + false + }; + + if let Some(doc) = item.doc_value() { + self.cnt = 0; + markdown::find_testable_code(doc, &mut *self); } + let ret = self.fold_item_recur(item); if pushed { self.names.pop(); } + return ret; + + // FIXME: it would be better to not have the escaped version in the first place + fn unescape_for_testname(mut s: String) -> String { + // for refs `&foo` + if s.contains("&") { + s = s.replace("&", "&"); + + // `::&'a mut Foo::` looks weird, let's make it `::<&'a mut Foo>`:: + if let Some('&') = s.chars().nth(0) { + s = format!("<{}>", s); + } + } + + // either `<..>` or `->` + if s.contains(">") { + s.replace(">", ">") + .replace("<", "<") + } else { + s + } + } + + fn typename_if_impl(item: &clean::Item) -> Option { + if let clean::ItemEnum::ImplItem(ref impl_) = item.inner { + let path = impl_.for_.to_string(); + let unescaped_path = unescape_for_testname(path); + Some(unescaped_path) + } else { + None + } + } } }