Skip to content

Commit 4202615

Browse files
committed
librustdoc: improve testnames for doctests
1 parent 11e55e4 commit 4202615

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed

src/librustdoc/clean/mod.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -2568,8 +2568,18 @@ fn resolve_type(cx: &DocContext,
25682568
debug!("resolve_type({:?},{:?})", path, id);
25692569
let tcx = match cx.tcx_opt() {
25702570
Some(tcx) => tcx,
2571-
// If we're extracting tests, this return value doesn't matter.
2572-
None => return Primitive(Bool),
2571+
// If we're extracting tests, this return value's accuracy is not
2572+
// important, all we want is a string representation to help people
2573+
// figure out what doctests are failing.
2574+
None => {
2575+
let did = DefId::local(DefIndex::from_u32(0));
2576+
return ResolvedPath {
2577+
path: path,
2578+
typarams: None,
2579+
did: did,
2580+
is_generic: false
2581+
};
2582+
}
25732583
};
25742584
let def = match tcx.def_map.borrow().get(&id) {
25752585
Some(k) => k.full_def(),

src/librustdoc/test.rs

+47-10
Original file line numberDiff line numberDiff line change
@@ -422,22 +422,59 @@ impl Collector {
422422

423423
impl DocFolder for Collector {
424424
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
425-
let pushed = match item.name {
426-
Some(ref name) if name.is_empty() => false,
427-
Some(ref name) => { self.names.push(name.to_string()); true }
428-
None => false
425+
let current_name = match item.name {
426+
Some(ref name) if !name.is_empty() => Some(name.clone()),
427+
_ => typename_if_impl(&item)
429428
};
430-
match item.doc_value() {
431-
Some(doc) => {
432-
self.cnt = 0;
433-
markdown::find_testable_code(doc, &mut *self);
434-
}
435-
None => {}
429+
430+
let pushed = if let Some(name) = current_name {
431+
self.names.push(name);
432+
true
433+
} else {
434+
false
435+
};
436+
437+
if let Some(doc) = item.doc_value() {
438+
self.cnt = 0;
439+
markdown::find_testable_code(doc, &mut *self);
436440
}
441+
437442
let ret = self.fold_item_recur(item);
438443
if pushed {
439444
self.names.pop();
440445
}
446+
441447
return ret;
448+
449+
// FIXME: it would be better to not have the escaped version in the first place
450+
fn unescape_for_testname(mut s: String) -> String {
451+
// for refs `&foo`
452+
if s.contains("&amp;") {
453+
s = s.replace("&amp;", "&");
454+
455+
// `::&'a mut Foo::` looks weird, let's make it `::<&'a mut Foo>`::
456+
if let Some('&') = s.chars().nth(0) {
457+
s = format!("<{}>", s);
458+
}
459+
}
460+
461+
// either `<..>` or `->`
462+
if s.contains("&gt;") {
463+
s.replace("&gt;", ">")
464+
.replace("&lt;", "<")
465+
} else {
466+
s
467+
}
468+
}
469+
470+
fn typename_if_impl(item: &clean::Item) -> Option<String> {
471+
if let clean::ItemEnum::ImplItem(ref impl_) = item.inner {
472+
let path = impl_.for_.to_string();
473+
let unescaped_path = unescape_for_testname(path);
474+
Some(unescaped_path)
475+
} else {
476+
None
477+
}
478+
}
442479
}
443480
}

0 commit comments

Comments
 (0)