Skip to content

Commit 583e460

Browse files
committed
coverage: Restrict empty-span expansion to only cover { and }
1 parent 71db4c5 commit 583e460

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

+42-28
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

-1
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)]

compiler/rustc_span/src/source_map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ impl SourceMap {
534534
/// Extracts the source surrounding the given `Span` using the `extract_source` function. The
535535
/// extract function takes three arguments: a string slice containing the source, an index in
536536
/// the slice for the beginning of the span and an index in the slice for the end of the span.
537-
fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
537+
pub fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
538538
where
539539
F: Fn(&str, usize, usize) -> Result<T, SpanSnippetError>,
540540
{

tests/coverage-run-rustdoc/doctest.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ $DIR/doctest.rs:
4545
LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() {
4646
LL| 1|//! println!("{:?}", res);
4747
LL| 1|//! }
48-
^0
48+
^0
4949
LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() {
5050
LL| 1|//! res = Ok(1);
5151
LL| 1|//! }
52-
^0
52+
^0
5353
LL| 1|//! res = Ok(0);
5454
LL| |//! }
5555
LL| |//! // need to be explicit because rustdoc cant infer the return type

tests/coverage/abort.cov-map

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Function name: abort::main
2-
Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
2+
Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 09, 00, 0a, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 30, 00, 31, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 30, 00, 31, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
33
Number of files: 1
44
- file 0 => global file 1
55
Number of expressions: 10
@@ -20,17 +20,17 @@ Number of file 0 mappings: 13
2020
- Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25)
2121
= ((c0 + (c1 + c2)) - c3)
2222
- Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10)
23-
- Code(Expression(3, Sub)) at (prev + 2, 10) to (start + 0, 11)
23+
- Code(Expression(3, Sub)) at (prev + 2, 9) to (start + 0, 10)
2424
= (((c0 + (c1 + c2)) - c3) - c4)
2525
- Code(Expression(8, Sub)) at (prev + 2, 12) to (start + 0, 25)
2626
= ((c0 + (c1 + c2)) - c3)
2727
- Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49)
28-
- Code(Expression(6, Sub)) at (prev + 0, 49) to (start + 0, 50)
28+
- Code(Expression(6, Sub)) at (prev + 0, 48) to (start + 0, 49)
2929
= (((c0 + (c1 + c2)) - c3) - c5)
3030
- Code(Expression(8, Sub)) at (prev + 4, 12) to (start + 0, 25)
3131
= ((c0 + (c1 + c2)) - c3)
3232
- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49)
33-
- Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50)
33+
- Code(Counter(2)) at (prev + 0, 48) to (start + 0, 49)
3434
- Code(Expression(9, Add)) at (prev + 1, 9) to (start + 0, 23)
3535
= (c1 + c2)
3636
- Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2)

tests/coverage/abort.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
LL| 6| }
1919
LL| | // See discussion (below the `Notes` section) on coverage results for the closing brace.
2020
LL| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
21-
^4 ^6
21+
^4 ^6
2222
LL| | // For the following example, the closing brace is the last character on the line.
2323
LL| | // This shows the character after the closing brace is highlighted, even if that next
2424
LL| | // character is a newline.
2525
LL| 10| if countdown < 5 { might_abort(false); }
26-
^4 ^6
26+
^4 ^6
2727
LL| 10| countdown -= 1;
2828
LL| | }
2929
LL| 1| Ok(())

tests/coverage/assert.cov-map

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Function name: assert::main
2-
Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02]
2+
Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02]
33
Number of files: 1
44
- file 0 => global file 1
55
Number of expressions: 8
@@ -21,7 +21,7 @@ Number of file 0 mappings: 9
2121
- Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32)
2222
= (((c0 + (c1 + (c2 + c3))) - c4) - c1)
2323
- Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10)
24-
- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11)
24+
- Code(Counter(3)) at (prev + 2, 9) to (start + 0, 10)
2525
- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23)
2626
= (c1 + (c2 + c3))
2727
- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)

tests/coverage/async2.cov-map

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ Number of file 0 mappings: 1
88
Highest counter ID seen: c0
99

1010
Function name: async2::async_func::{closure#0}
11-
Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02]
11+
Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02]
1212
Number of files: 1
1313
- file 0 => global file 1
1414
Number of expressions: 0
1515
Number of file 0 mappings: 4
1616
- Code(Counter(0)) at (prev + 16, 23) to (start + 3, 9)
1717
- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
18-
- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
18+
- Code(Zero) at (prev + 2, 5) to (start + 0, 6)
1919
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
2020
Highest counter ID seen: c1
2121

@@ -47,14 +47,14 @@ Number of file 0 mappings: 1
4747
Highest counter ID seen: c0
4848

4949
Function name: async2::non_async_func
50-
Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02]
50+
Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02]
5151
Number of files: 1
5252
- file 0 => global file 1
5353
Number of expressions: 0
5454
Number of file 0 mappings: 4
5555
- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 9)
5656
- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
57-
- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
57+
- Code(Zero) at (prev + 2, 5) to (start + 0, 6)
5858
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
5959
Highest counter ID seen: c1
6060

tests/coverage/async2.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
LL| 1| if b {
1212
LL| 1| println!("non_async_func println in block");
1313
LL| 1| }
14-
^0
14+
^0
1515
LL| 1|}
1616
LL| |
1717
LL| 1|async fn async_func() {
@@ -20,7 +20,7 @@
2020
LL| 1| if b {
2121
LL| 1| println!("async_func println in block");
2222
LL| 1| }
23-
^0
23+
^0
2424
LL| 1|}
2525
LL| |
2626
LL| 1|async fn async_func_just_println() {

tests/coverage/branch/if.cov-map

+9-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Number of file 0 mappings: 8
2525
Highest counter ID seen: c4
2626

2727
Function name: if::branch_not
28-
Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 06, 00, 07, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 05, 01, 01, 00, 02]
28+
Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 05, 00, 06, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 05, 00, 06, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 05, 00, 06, 05, 01, 01, 00, 02]
2929
Number of files: 1
3030
- file 0 => global file 1
3131
Number of expressions: 7
@@ -43,34 +43,34 @@ Number of file 0 mappings: 18
4343
true = c2
4444
false = (c1 - c2)
4545
- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17)
46-
- Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7)
46+
- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6)
4747
= (c1 - c2)
4848
- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 10)
4949
- Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10)
5050
true = (c1 - c3)
5151
false = c3
5252
- Code(Expression(2, Sub)) at (prev + 0, 11) to (start + 2, 6)
5353
= (c1 - c3)
54-
- Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7)
54+
- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 6)
5555
- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 11)
5656
- Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 8) to (start + 0, 11)
5757
true = c4
5858
false = (c1 - c4)
5959
- Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6)
60-
- Code(Expression(4, Sub)) at (prev + 2, 6) to (start + 0, 7)
60+
- Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 6)
6161
= (c1 - c4)
6262
- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 12)
6363
- Branch { true: Expression(6, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12)
6464
true = (c1 - c5)
6565
false = c5
6666
- Code(Expression(6, Sub)) at (prev + 0, 13) to (start + 2, 6)
6767
= (c1 - c5)
68-
- Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7)
68+
- Code(Counter(5)) at (prev + 2, 5) to (start + 0, 6)
6969
- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
7070
Highest counter ID seen: c5
7171

7272
Function name: if::branch_not_as
73-
Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 06, 00, 07, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 06, 00, 07, 05, 01, 01, 00, 02]
73+
Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 05, 00, 06, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 05, 00, 06, 05, 01, 01, 00, 02]
7474
Number of files: 1
7575
- file 0 => global file 1
7676
Number of expressions: 5
@@ -87,21 +87,21 @@ Number of file 0 mappings: 14
8787
false = c2
8888
- Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6)
8989
= (c1 - c2)
90-
- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
90+
- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 6)
9191
- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 21)
9292
- Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 8) to (start + 0, 21)
9393
true = c3
9494
false = (c1 - c3)
9595
- Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6)
96-
- Code(Expression(2, Sub)) at (prev + 2, 6) to (start + 0, 7)
96+
- Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 0, 6)
9797
= (c1 - c3)
9898
- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 22)
9999
- Branch { true: Expression(4, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22)
100100
true = (c1 - c4)
101101
false = c4
102102
- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 2, 6)
103103
= (c1 - c4)
104-
- Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7)
104+
- Code(Counter(4)) at (prev + 2, 5) to (start + 0, 6)
105105
- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
106106
Highest counter ID seen: c4
107107

tests/coverage/branch/if.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
------------------
3131
LL| 2| say("not not a");
3232
LL| 2| }
33-
^1
33+
^1
3434
LL| 3| if !!!a {
3535
------------------
3636
| Branch (LL:8): [True: 1, False: 2]
@@ -54,7 +54,7 @@
5454
------------------
5555
LL| 2| say("not not (a as bool)");
5656
LL| 2| }
57-
^1
57+
^1
5858
LL| 3| if !!!(a as bool) {
5959
------------------
6060
| Branch (LL:8): [True: 1, False: 2]

0 commit comments

Comments
 (0)