Skip to content

Commit 3c1124e

Browse files
authored
Wrong coverage for await foreach with generic method (#1312)
1 parent 2bb04f2 commit 3c1124e

File tree

4 files changed

+29
-7
lines changed

4 files changed

+29
-7
lines changed

Documentation/Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
9+
### Fixed
10+
-Await foreach has wrong branch coverage when method is generic [#1210](https://github.com/coverlet-coverage/coverlet/issues/1210)
11+
712
## Release date 2022-02-06
813
### Packages
914
coverlet.msbuild 3.1.2

src/coverlet.core/Symbols/CecilSymbolHelper.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,11 @@ static bool CheckForAsyncEnumerator(List<Instruction> instructions, Instruction
496496
(instructions[currentIndex - 2].OpCode == OpCodes.Ldarg ||
497497
instructions[currentIndex - 2].OpCode == OpCodes.Ldarg_0) &&
498498
instructions[currentIndex - 1].OpCode == OpCodes.Ldfld &&
499-
instructions[currentIndex - 1].Operand is FieldDefinition field &&
500-
IsCompilerGenerated(field) && field.FieldType.FullName.StartsWith("System.Collections.Generic.IAsyncEnumerator"))
499+
(
500+
(instructions[currentIndex - 1].Operand is FieldDefinition field && IsCompilerGenerated(field) && field.FieldType.FullName.StartsWith("System.Collections.Generic.IAsyncEnumerator")) ||
501+
(instructions[currentIndex - 1].Operand is FieldReference fieldRef && IsCompilerGenerated(fieldRef.Resolve()) && fieldRef.FieldType.FullName.StartsWith("System.Collections.Generic.IAsyncEnumerator"))
502+
)
503+
)
501504
{
502505
return true;
503506
}
@@ -538,8 +541,10 @@ static bool CheckIfExceptionThrown(List<Instruction> instructions, Instruction i
538541
for (int i = currentIndex - 1; i >= minFieldIndex; --i)
539542
{
540543
if (instructions[i].OpCode == OpCodes.Ldfld &&
541-
instructions[i].Operand is FieldDefinition field &&
542-
IsCompilerGenerated(field) && field.FieldType.FullName == "System.Object")
544+
(
545+
(instructions[i].Operand is FieldDefinition field && IsCompilerGenerated(field) && field.FieldType.FullName == "System.Object") ||
546+
(instructions[i].Operand is FieldReference fieldRef && IsCompilerGenerated(fieldRef.Resolve()) && fieldRef.FieldType.FullName == "System.Object")
547+
))
543548
{
544549
// We expect the call to GetResult() to be no more than four
545550
// instructions before the loading of the field's value.

test/coverlet.core.tests/Coverage/CoverageTests.AsyncForeach.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public void AsyncForeach()
2424
int res = ((ValueTask<int>)instance.SumWithATwist(AsyncEnumerable.Range(1, 5))).GetAwaiter().GetResult();
2525
res += ((ValueTask<int>)instance.Sum(AsyncEnumerable.Range(1, 3))).GetAwaiter().GetResult();
2626
res += ((ValueTask<int>)instance.SumEmpty()).GetAwaiter().GetResult();
27+
((ValueTask)instance.GenericAsyncForeach<object>(AsyncEnumerable.Range(1, 3))).GetAwaiter().GetResult();
2728

2829
return Task.CompletedTask;
2930
}, persistPrepareResultToFile: pathSerialize[0]);
@@ -43,7 +44,9 @@ public void AsyncForeach()
4344
// Sum(IAsyncEnumerable<int>)
4445
(34, 1), (35, 1), (37, 9), (38, 3), (39, 3), (40, 3), (42, 1), (43, 1),
4546
// SumEmpty()
46-
(47, 1), (48, 1), (50, 3), (51, 0), (52, 0), (53, 0), (55, 1), (56, 1)
47+
(47, 1), (48, 1), (50, 3), (51, 0), (52, 0), (53, 0), (55, 1), (56, 1),
48+
// GenericAsyncForeach
49+
(59,1), (60, 9), (61, 3), (62, 3), (63, 3), (64, 1)
4750
)
4851
.AssertBranchesCovered(BuildConfiguration.Debug,
4952
// SumWithATwist(IAsyncEnumerable<int>)
@@ -53,9 +56,10 @@ public void AsyncForeach()
5356
// SumEmpty()
5457
// If we never entered the loop, that's a branch not taken, which is
5558
// what we want to see.
56-
(50, 0, 1), (50, 1, 0)
59+
(50, 0, 1), (50, 1, 0),
60+
(60, 0, 1), (60, 1, 3)
5761
)
58-
.ExpectedTotalNumberOfBranches(BuildConfiguration.Debug, 4);
62+
.ExpectedTotalNumberOfBranches(BuildConfiguration.Debug, 5);
5963
}
6064
finally
6165
{

test/coverlet.core.tests/Samples/Instrumentation.AsyncForeach.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,13 @@ async public ValueTask<int> SumEmpty()
5454

5555
return sum;
5656
}
57+
58+
public async ValueTask GenericAsyncForeach<T>(IAsyncEnumerable<int> ints)
59+
{
60+
await foreach (int obj in ints)
61+
{
62+
await Task.Delay(1);
63+
}
64+
}
5765
}
5866
}

0 commit comments

Comments
 (0)