@@ -22,7 +22,7 @@ use rustc_middle::mir::{
22
22
use rustc_middle:: ty:: TyCtxt ;
23
23
use rustc_span:: def_id:: LocalDefId ;
24
24
use rustc_span:: source_map:: SourceMap ;
25
- use rustc_span:: { BytePos , Pos , RelativeBytePos , SourceFile , Span } ;
25
+ use rustc_span:: { BytePos , Pos , SourceFile , Span } ;
26
26
use tracing:: { debug, debug_span, trace} ;
27
27
28
28
use crate :: coverage:: counters:: { CounterIncrementSite , CoverageCounters } ;
@@ -391,6 +391,41 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
391
391
data. statements . insert ( 0 , statement) ;
392
392
}
393
393
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
+
394
429
/// Converts the span into its start line and column, and end line and column.
395
430
///
396
431
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
@@ -407,44 +442,23 @@ fn make_source_region(
407
442
file : & SourceFile ,
408
443
span : Span ,
409
444
) -> Option < SourceRegion > {
445
+ let span = ensure_non_empty_span ( source_map, hir_info, span) ?;
446
+
410
447
let lo = span. lo ( ) ;
411
448
let hi = span. hi ( ) ;
412
449
413
450
// Column numbers need to be in bytes, so we can't use the more convenient
414
451
// `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 ) > {
416
453
let rpos = file. relative_position ( pos) ;
417
454
let line_index = file. lookup_line ( rpos) ?;
418
455
let line_start = file. lines ( ) [ line_index] ;
419
456
// 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 ) )
421
458
} ;
422
459
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) ?;
448
462
449
463
// Apply an offset so that code in doctests has correct line numbers.
450
464
// FIXME(#79417): Currently we have no way to offset doctest _columns_.
0 commit comments