Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e25a65c

Browse files
committedNov 8, 2024·
coverage: Restrict empty-span expansion to only cover { and }
1 parent 29dcd71 commit e25a65c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+200
-189
lines changed
 

‎compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_middle::mir::{
2222
use rustc_middle::ty::TyCtxt;
2323
use rustc_span::def_id::LocalDefId;
2424
use rustc_span::source_map::SourceMap;
25-
use rustc_span::{BytePos, Pos, RelativeBytePos, SourceFile, Span};
25+
use rustc_span::{BytePos, Pos, SourceFile, Span};
2626
use tracing::{debug, debug_span, trace};
2727

2828
use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
@@ -391,6 +391,41 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
391391
data.statements.insert(0, statement);
392392
}
393393

394+
fn ensure_non_empty_span(
395+
source_map: &SourceMap,
396+
hir_info: &ExtractedHirInfo,
397+
span: Span,
398+
) -> Option<Span> {
399+
if !span.is_empty() {
400+
return Some(span);
401+
}
402+
403+
let lo = span.lo();
404+
let hi = span.hi();
405+
406+
// The span is empty, so try to expand it to cover an adjacent '{' or '}',
407+
// but only within the bounds of the body span.
408+
let try_next = hi < hir_info.body_span.hi();
409+
let try_prev = hir_info.body_span.lo() < lo;
410+
if !(try_next || try_prev) {
411+
return None;
412+
}
413+
414+
source_map
415+
.span_to_source(span, |src, start, end| try {
416+
// We're only checking for specific ASCII characters, so we don't
417+
// have to worry about multi-byte code points.
418+
if try_next && src.as_bytes()[end] == b'{' {
419+
Some(span.with_hi(hi + BytePos(1)))
420+
} else if try_prev && src.as_bytes()[start - 1] == b'}' {
421+
Some(span.with_lo(lo - BytePos(1)))
422+
} else {
423+
None
424+
}
425+
})
426+
.ok()?
427+
}
428+
394429
/// Converts the span into its start line and column, and end line and column.
395430
///
396431
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
@@ -407,44 +442,23 @@ fn make_source_region(
407442
file: &SourceFile,
408443
span: Span,
409444
) -> Option<SourceRegion> {
445+
let span = ensure_non_empty_span(source_map, hir_info, span)?;
446+
410447
let lo = span.lo();
411448
let hi = span.hi();
412449

413450
// Column numbers need to be in bytes, so we can't use the more convenient
414451
// `SourceMap` methods for looking up file coordinates.
415-
let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> {
452+
let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
416453
let rpos = file.relative_position(pos);
417454
let line_index = file.lookup_line(rpos)?;
418455
let line_start = file.lines()[line_index];
419456
// Line numbers and column numbers are 1-based, so add 1 to each.
420-
Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1))
457+
Some((line_index + 1, (rpos - line_start).to_usize() + 1))
421458
};
422459

423-
let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?;
424-
let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?;
425-
426-
// If the span is empty, try to expand it horizontally by one character's
427-
// worth of bytes, so that it is more visible in `llvm-cov` reports.
428-
// We do this after resolving line/column numbers, so that empty spans at the
429-
// end of a line get an extra column instead of wrapping to the next line.
430-
let body_span = hir_info.body_span;
431-
if span.is_empty()
432-
&& body_span.contains(span)
433-
&& let Some(src) = &file.src
434-
{
435-
// Prefer to expand the end position, if it won't go outside the body span.
436-
if hi < body_span.hi() {
437-
let hi_rpos = hi_rpos.to_usize();
438-
let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos;
439-
end_col += nudge_bytes;
440-
} else if lo > body_span.lo() {
441-
let lo_rpos = lo_rpos.to_usize();
442-
let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1);
443-
// Subtract the nudge, but don't go below column 1.
444-
start_col = start_col.saturating_sub(nudge_bytes).max(1);
445-
}
446-
// If neither nudge could be applied, stick with the empty span coordinates.
447-
}
460+
let (mut start_line, start_col) = line_and_byte_column(lo)?;
461+
let (mut end_line, end_col) = line_and_byte_column(hi)?;
448462

449463
// Apply an offset so that code in doctests has correct line numbers.
450464
// FIXME(#79417): Currently we have no way to offset doctest _columns_.

‎compiler/rustc_mir_transform/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#![feature(let_chains)]
1010
#![feature(map_try_insert)]
1111
#![feature(never_type)]
12-
#![feature(round_char_boundary)]
1312
#![feature(try_blocks)]
1413
#![feature(yeet_expr)]
1514
#![warn(unreachable_pub)]

0 commit comments

Comments
 (0)
Please sign in to comment.