coverage: Simplify the heuristic for ignoring async fn return spans

This commit is contained in:
Zalathar 2023-12-06 18:40:06 +11:00
parent 5ea62560f2
commit e0cd8057c8
2 changed files with 14 additions and 17 deletions

View File

@ -319,29 +319,16 @@ fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
} }
} }
let prev = self.take_prev();
debug!(" AT END, adding last prev={prev:?}");
// Drain any remaining dups into the output. // Drain any remaining dups into the output.
for dup in self.pending_dups.drain(..) { for dup in self.pending_dups.drain(..) {
debug!(" ...adding at least one pending dup={:?}", dup); debug!(" ...adding at least one pending dup={:?}", dup);
self.refined_spans.push(dup); self.refined_spans.push(dup);
} }
// Async functions wrap a closure that implements the body to be executed. The enclosing // There is usually a final span remaining in `prev` after the loop ends,
// function is called and returns an `impl Future` without initially executing any of the // so add it to the output as well.
// body. To avoid showing the return from the enclosing function as a "covered" return from if let Some(prev) = self.some_prev.take() {
// the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is debug!(" AT END, adding last prev={prev:?}");
// excluded. The closure's `Return` is the only one that will be counted. This provides
// adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
// of the function body.)
let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
} else {
false
};
if !body_ends_with_closure {
self.refined_spans.push(prev); self.refined_spans.push(prev);
} }

View File

@ -44,6 +44,16 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
}); });
// The desugaring of an async function includes a closure containing the
// original function body, and a terminator that returns the `impl Future`.
// That terminator will cause a confusing coverage count for the function's
// closing brace, so discard everything after the body closure span.
if let Some(body_closure_index) =
initial_spans.iter().rposition(|covspan| covspan.is_closure && covspan.span == body_span)
{
initial_spans.truncate(body_closure_index + 1);
}
initial_spans initial_spans
} }