Coverlet: Closing bracket uncovered in try-catch statement when exception is re-thrown in catch

Created on 11 Jun 2019  路  8Comments  路  Source: coverlet-coverage/coverlet

The closing bracket is showing up as uncovered when I re-throw an exception from a catch statement. Is this expected behavior? The closing bracket is technically unreachable code, and it prevents me from reaching 100% coverage on the method when coverlet says it is uncovered by a test.

{
...
}
catch (Exception)
{
    // handle exception (retry/log/etc.)

    throw;
} // ** uncovered line **
enhancement tenet-coverage up-for-grabs

All 8 comments

Can you produce a simple repro?(similar to https://github.com/abe545/CoverletAwaitBranchCoverage)
Coverlet results are based on generated pdb(where we don't have control), to understand if it's a bug we would need a repro.

This only seems to be an issue when there is an await inside the catch block. Here is a repro:

https://github.com/brpratt/CoverletAwaitThrowInsideCatch

From the generated code, it seems there is a branch while deciding how to re-throw the exception. In the linked example, maybe this is the offender?

Exception ex = <>s__1 as Exception;
if (ex == null)
{
    throw <>s__1;
}
ExceptionDispatchInfo.Capture(ex).Throw();

Thank's for repro...I'll let you know what I discover.

did some check...and seem that result is expected for both cases sync and async, I mean if exception throws code rewind and so we cannot reach end of a method.
The only "incorrect" thing that I see is the branches on emtpy catch and on throw that is autogenerated, I don't know if I we can remove those noise without risk to remove "non false positive" I'll check what we can do.
TL;DR; The issue with this edge cases is that the pattern of compilers could change in future and if we're to much "aggressive" on "not so clear autogenerated code pattern" we risk to intruduce bug where a branch/line is reported wronlgy covered.

1
2

and it prevents me from reaching 100% coverage

In code coverage 100% covered is not a goal, we should reach and acceptable level and verify when that value drop.

Compiler generated code is below, at the moment I don't know how to recognize and filter branches out without remove other possible real branches.
Move issue level from bug to enhancement, I mean branches are real there is a mismatch between c# and IL.

// Coverlet.Core.Samples.Tests.CatchThrow
// Token: 0x06000021 RID: 33 RVA: 0x00002FF4 File Offset: 0x000011F4
public async Task<int> ParseAsync(string str)
{
    int num = 0;
    object obj2;
    try
    {
        return int.Parse(str);
    }
    catch (object obj)
    {
        obj2 = obj;
        num = 1;
    }
    int num2 = num;
    if (num2 == 1)
    {
        await Task.Delay(0);
        Exception ex = obj2 as Exception;
        if (ex == null)
        {
            throw obj2;
        }
        ExceptionDispatchInfo.Capture(ex).Throw();
    }
    obj2 = null;
    int result;
    return result;
}

I am experiencing the same problem. Doesn't seem too much like an edge case because it happens in all cases where there is a return statement before closing brackets and some opening brackets.

Why is line 20 not considered for code coverage at all but line 21 is?
Obviously there are other coverage issues in this picture, but that discrepancy jumps out at me the most.

image

@NoahApplebaum some questions, version of coverlet?Debug or release?Can you specify your "test" or better provide full repro(tests) with method above?

Updated my coverlet.msbuild and it works! Thanks @MarcoRossignoli

Was this page helpful?
0 / 5 - 0 ratings