Skip to content

Commit d542718

Browse files
committed
Refactoring for record + primary constructors
1 parent 0a2024d commit d542718

File tree

6 files changed

+459
-95
lines changed

6 files changed

+459
-95
lines changed

src/coverlet.core/Symbols/CecilSymbolHelper.cs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,10 +1364,9 @@ private bool SkipExpressionBreakpointsSequences(MethodDefinition methodDefinitio
13641364

13651365
public bool SkipInlineAssignedAutoProperty(bool skipAutoProps, MethodDefinition methodDefinition, Instruction instruction)
13661366
{
1367-
if (!skipAutoProps || !methodDefinition.IsConstructor) return false;
1367+
if (!skipAutoProps) return false;
13681368

1369-
return SkipGeneratedBackingFieldAssignment(methodDefinition, instruction) ||
1370-
SkipDefaultInitializationSystemObject(instruction);
1369+
return SkipGeneratedBackingFieldAssignment(methodDefinition, instruction);
13711370
}
13721371

13731372
private static bool SkipGeneratedBackingFieldAssignment(MethodDefinition methodDefinition, Instruction instruction)
@@ -1401,22 +1400,6 @@ instance void .ctor () cil managed
14011400
autogeneratedBackingFields.Select(x => x.FullName).Contains(fr.FullName);
14021401
}
14031402

1404-
private static bool SkipDefaultInitializationSystemObject(Instruction instruction)
1405-
{
1406-
/*
1407-
A type always has a constructor with a default instantiation of System.Object. For record types these
1408-
instructions can have a own sequence point. This means that even the default constructor would be instrumented.
1409-
To skip this we search for call instructions with a method reference that declares System.Object.
1410-
1411-
IL_0000: ldarg.0
1412-
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
1413-
IL_0006: ret
1414-
*/
1415-
return instruction.OpCode == OpCodes.Ldarg &&
1416-
instruction.Next?.OpCode == OpCodes.Call &&
1417-
instruction.Next?.Operand is MethodReference mr && mr.DeclaringType.FullName.Equals(typeof(System.Object).FullName);
1418-
}
1419-
14201403
private static bool SkipBranchGeneratedExceptionFilter(Instruction branchInstruction, MethodDefinition methodDefinition)
14211404
{
14221405
if (!methodDefinition.Body.HasExceptionHandlers)

test/coverlet.core.coverage.tests/Coverage/CoverageTests.AutoProps.cs

Lines changed: 91 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,20 @@ public partial class CoverageTests
1616
[Theory]
1717
[InlineData(true)]
1818
[InlineData(false)]
19-
public void SkipAutoProps(bool skipAutoProps)
19+
public void SkipClassWithAutoProps(bool skipAutoProps)
2020
{
2121
string path = Path.GetTempFileName();
2222
try
2323
{
2424
FunctionExecutor.Run(async (string[] parameters) =>
2525
{
26-
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<AutoProps>(instance =>
26+
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithAutoProps>(instance =>
2727
{
2828
instance.AutoPropsNonInit = 10;
2929
instance.AutoPropsInit = 20;
3030
int readValue = instance.AutoPropsNonInit;
3131
readValue = instance.AutoPropsInit;
32+
readValue = instance.AutoPropsInitKeyword;
3233
return Task.CompletedTask;
3334
},
3435
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));
@@ -40,8 +41,8 @@ public void SkipAutoProps(bool skipAutoProps)
4041
{
4142
TestInstrumentationHelper.GetCoverageResult(path)
4243
.Document("Instrumentation.AutoProps.cs")
43-
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 12, 13)
44-
.AssertNonInstrumentedLines(BuildConfiguration.Release, 12, 13)
44+
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 12, 14)
45+
.AssertNonInstrumentedLines(BuildConfiguration.Release, 12, 14)
4546
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 9, 11)
4647
.AssertLinesCovered(BuildConfiguration.Debug, (7, 1))
4748
.AssertLinesCovered(BuildConfiguration.Release, (10, 1));
@@ -50,9 +51,9 @@ public void SkipAutoProps(bool skipAutoProps)
5051
{
5152
TestInstrumentationHelper.GetCoverageResult(path)
5253
.Document("Instrumentation.AutoProps.cs")
53-
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 7, 13)
54+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 7, 14)
5455
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 10, 10)
55-
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 12, 13);
56+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 12, 14);
5657
}
5758
}
5859
finally
@@ -64,42 +65,39 @@ public void SkipAutoProps(bool skipAutoProps)
6465
[Theory]
6566
[InlineData(true)]
6667
[InlineData(false)]
67-
public void SkipAutoPropsInRecords(bool skipAutoProps)
68+
public void SkipClassWithAutoPropsPrimaryConstructor(bool skipAutoProps)
6869
{
6970
string path = Path.GetTempFileName();
7071
try
7172
{
7273
FunctionExecutor.Run(async (string[] parameters) =>
7374
{
74-
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<RecordWithPropertyInit>(instance =>
75-
{
76-
instance.RecordAutoPropsNonInit = string.Empty;
77-
instance.RecordAutoPropsInit = string.Empty;
78-
string readValue = instance.RecordAutoPropsInit;
79-
readValue = instance.RecordAutoPropsNonInit;
80-
return Task.CompletedTask;
81-
},
82-
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));
75+
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithAutoPropsPrimaryConstructor>(instance =>
76+
{
77+
return Task.CompletedTask;
78+
},
79+
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));
8380

8481
return 0;
8582
}, [path, skipAutoProps.ToString()]);
8683

8784
if (skipAutoProps)
8885
{
8986
TestInstrumentationHelper.GetCoverageResult(path)
90-
.Document("Instrumentation.AutoProps.cs")
91-
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 23, 24)
92-
.AssertNonInstrumentedLines(BuildConfiguration.Release, 23, 24)
93-
.AssertLinesCovered(BuildConfiguration.Debug, (18, 1), (20, 1), (21, 1), (22, 1))
94-
.AssertLinesCovered(BuildConfiguration.Release, (21, 1));
87+
.Document("Instrumentation.AutoProps.cs")
88+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 28, 28)
89+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 28, 28)
90+
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 30, 31, 32)
91+
.AssertNonInstrumentedLines(BuildConfiguration.Release, 30, 31, 32);
9592
}
9693
else
9794
{
9895
TestInstrumentationHelper.GetCoverageResult(path)
99-
.Document("Instrumentation.AutoProps.cs")
100-
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 18, 24)
101-
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 21, 21)
102-
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 23, 24);
96+
.Document("Instrumentation.AutoProps.cs")
97+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 28, 28)
98+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 30, 32)
99+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 28, 28)
100+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 30, 32);
103101
}
104102
}
105103
finally
@@ -111,37 +109,44 @@ public void SkipAutoPropsInRecords(bool skipAutoProps)
111109
[Theory]
112110
[InlineData(true)]
113111
[InlineData(false)]
114-
public void SkipRecordWithProperties(bool skipAutoProps)
112+
public void SkipRecordWithAutoProps(bool skipAutoProps)
115113
{
116114
string path = Path.GetTempFileName();
117115
try
118116
{
119117
FunctionExecutor.Run(async (string[] parameters) =>
120118
{
121-
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithRecordsAutoProperties>(instance =>
122-
{
123-
return Task.CompletedTask;
124-
},
125-
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));
119+
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<RecordWithAutoProps>(instance =>
120+
{
121+
instance.AutoPropsNonInit = 10;
122+
instance.AutoPropsInit = 20;
123+
int readValue = instance.AutoPropsNonInit;
124+
readValue = instance.AutoPropsInit;
125+
readValue = instance.AutoPropsInitKeyword;
126+
return Task.CompletedTask;
127+
},
128+
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));
126129

127130
return 0;
128131
}, [path, skipAutoProps.ToString()]);
129132

130133
if (skipAutoProps)
131134
{
132135
TestInstrumentationHelper.GetCoverageResult(path)
133-
.Document("Instrumentation.AutoProps.cs")
134-
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 29, 29)
135-
.AssertNonInstrumentedLines(BuildConfiguration.Release, 29, 29)
136-
.AssertLinesCovered(BuildConfiguration.Debug, (32, 1), (33, 1), (34, 1))
137-
.AssertLinesCovered(BuildConfiguration.Release, (33, 1));
136+
.Document("Instrumentation.AutoProps.cs")
137+
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 43, 45)
138+
.AssertNonInstrumentedLines(BuildConfiguration.Release, 43, 45)
139+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 40, 42)
140+
.AssertLinesCovered(BuildConfiguration.Debug, (39, 1))
141+
.AssertLinesCovered(BuildConfiguration.Release, (39, 1));
138142
}
139143
else
140144
{
141145
TestInstrumentationHelper.GetCoverageResult(path)
142-
.Document("Instrumentation.AutoProps.cs")
143-
.AssertLinesCovered(BuildConfiguration.Debug, (29, 1), (31, 1), (32, 1), (33, 1), (34, 1))
144-
.AssertLinesCovered(BuildConfiguration.Release, (29, 1), (31, 1), (33, 1));
146+
.Document("Instrumentation.AutoProps.cs")
147+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 38, 45) // go on here
148+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 39, 39)
149+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 41, 45);
145150
}
146151
}
147152
finally
@@ -153,14 +158,14 @@ public void SkipRecordWithProperties(bool skipAutoProps)
153158
[Theory]
154159
[InlineData(true)]
155160
[InlineData(false)]
156-
public void SkipInheritingRecordsWithProperties(bool skipAutoProps)
161+
public void SkipRecordWithAutoPropsPrimaryConstructor(bool skipAutoProps)
157162
{
158163
string path = Path.GetTempFileName();
159164
try
160165
{
161166
FunctionExecutor.Run(async (string[] parameters) =>
162167
{
163-
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithInheritingRecordsAndAutoProperties>(instance =>
168+
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<RecordsWithPrimaryConstructor>(instance =>
164169
{
165170
return Task.CompletedTask;
166171
},
@@ -173,18 +178,57 @@ public void SkipInheritingRecordsWithProperties(bool skipAutoProps)
173178
{
174179
TestInstrumentationHelper.GetCoverageResult(path)
175180
.Document("Instrumentation.AutoProps.cs")
176-
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 39, 39)
177-
.AssertNonInstrumentedLines(BuildConfiguration.Release, 39, 39)
178-
.AssertLinesCovered(BuildConfiguration.Debug, (41, 1), (44, 1), (45, 1), (46, 1))
179-
.AssertLinesCovered(BuildConfiguration.Release, (45, 1));
181+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 50, 50)
182+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 50, 50);
183+
}
184+
else
185+
{
186+
TestInstrumentationHelper.GetCoverageResult(path)
187+
.Document("Instrumentation.AutoProps.cs")
188+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 50, 50)
189+
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 50, 50);
190+
}
191+
}
192+
finally
193+
{
194+
File.Delete(path);
195+
}
196+
}
180197

198+
[Theory]
199+
[InlineData(true)]
200+
[InlineData(false)]
201+
public void SkipRecordWithAutoPropsPrimaryConstructorMultiline(bool skipAutoProps)
202+
{
203+
string path = Path.GetTempFileName();
204+
try
205+
{
206+
FunctionExecutor.Run(async (string[] parameters) =>
207+
{
208+
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<RecordsWithPrimaryConstructor>(instance =>
209+
{
210+
return Task.CompletedTask;
211+
},
212+
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));
213+
214+
return 0;
215+
}, [path, skipAutoProps.ToString()]);
216+
217+
if (skipAutoProps)
218+
{
219+
TestInstrumentationHelper.GetCoverageResult(path)
220+
.Document("Instrumentation.AutoProps.cs")
221+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 52, 55)
222+
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 52, 55);
181223
}
182224
else
183225
{
184226
TestInstrumentationHelper.GetCoverageResult(path)
185227
.Document("Instrumentation.AutoProps.cs")
186-
.AssertLinesCovered(BuildConfiguration.Debug, (39, 1), (41, 1), (44, 1), (45, 1), (46, 1))
187-
.AssertLinesCovered(BuildConfiguration.Release, (39, 1), (41, 1), (45, 1));
228+
.AssertLinesCovered(BuildConfiguration.Debug, 52, 55)
229+
.AssertLinesNotCovered(BuildConfiguration.Debug, 53, 54)
230+
.AssertLinesCovered(BuildConfiguration.Release, 52, 55)
231+
.AssertLinesNotCovered(BuildConfiguration.Release, 53, 54);
188232
}
189233
}
190234
finally

0 commit comments

Comments
 (0)