Skip to content

Refactoring records + primary constructor instrumentation #1761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
21 changes: 2 additions & 19 deletions src/coverlet.core/Symbols/CecilSymbolHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1364,10 +1364,9 @@ private bool SkipExpressionBreakpointsSequences(MethodDefinition methodDefinitio

public bool SkipInlineAssignedAutoProperty(bool skipAutoProps, MethodDefinition methodDefinition, Instruction instruction)
{
if (!skipAutoProps || !methodDefinition.IsConstructor) return false;
if (!skipAutoProps) return false;

return SkipGeneratedBackingFieldAssignment(methodDefinition, instruction) ||
SkipDefaultInitializationSystemObject(instruction);
return SkipGeneratedBackingFieldAssignment(methodDefinition, instruction);
}

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

private static bool SkipDefaultInitializationSystemObject(Instruction instruction)
{
/*
A type always has a constructor with a default instantiation of System.Object. For record types these
instructions can have a own sequence point. This means that even the default constructor would be instrumented.
To skip this we search for call instructions with a method reference that declares System.Object.

IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
*/
return instruction.OpCode == OpCodes.Ldarg &&
instruction.Next?.OpCode == OpCodes.Call &&
instruction.Next?.Operand is MethodReference mr && mr.DeclaringType.FullName.Equals(typeof(System.Object).FullName);
}

private static bool SkipBranchGeneratedExceptionFilter(Instruction branchInstruction, MethodDefinition methodDefinition)
{
if (!methodDefinition.Body.HasExceptionHandlers)
Expand Down
132 changes: 0 additions & 132 deletions test/coverlet.core.coverage.tests/Coverage/CoverageTests.AutoProps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,137 +60,5 @@ public void SkipAutoProps(bool skipAutoProps)
File.Delete(path);
}
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void SkipAutoPropsInRecords(bool skipAutoProps)
{
string path = Path.GetTempFileName();
try
{
FunctionExecutor.Run(async (string[] parameters) =>
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<RecordWithPropertyInit>(instance =>
{
instance.RecordAutoPropsNonInit = string.Empty;
instance.RecordAutoPropsInit = string.Empty;
string readValue = instance.RecordAutoPropsInit;
readValue = instance.RecordAutoPropsNonInit;
return Task.CompletedTask;
},
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));

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

if (skipAutoProps)
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 23, 24)
.AssertNonInstrumentedLines(BuildConfiguration.Release, 23, 24)
.AssertLinesCovered(BuildConfiguration.Debug, (18, 1), (20, 1), (21, 1), (22, 1))
.AssertLinesCovered(BuildConfiguration.Release, (21, 1));
}
else
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertLinesCoveredFromTo(BuildConfiguration.Debug, 18, 24)
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 21, 21)
.AssertLinesCoveredFromTo(BuildConfiguration.Release, 23, 24);
}
}
finally
{
File.Delete(path);
}
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void SkipRecordWithProperties(bool skipAutoProps)
{
string path = Path.GetTempFileName();
try
{
FunctionExecutor.Run(async (string[] parameters) =>
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithRecordsAutoProperties>(instance =>
{
return Task.CompletedTask;
},
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));

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

if (skipAutoProps)
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 29, 29)
.AssertNonInstrumentedLines(BuildConfiguration.Release, 29, 29)
.AssertLinesCovered(BuildConfiguration.Debug, (32, 1), (33, 1), (34, 1))
.AssertLinesCovered(BuildConfiguration.Release, (33, 1));
}
else
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertLinesCovered(BuildConfiguration.Debug, (29, 1), (31, 1), (32, 1), (33, 1), (34, 1))
.AssertLinesCovered(BuildConfiguration.Release, (29, 1), (31, 1), (33, 1));
}
}
finally
{
File.Delete(path);
}
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void SkipInheritingRecordsWithProperties(bool skipAutoProps)
{
string path = Path.GetTempFileName();
try
{
FunctionExecutor.Run(async (string[] parameters) =>
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithInheritingRecordsAndAutoProperties>(instance =>
{
return Task.CompletedTask;
},
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));

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

if (skipAutoProps)
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 39, 39)
.AssertNonInstrumentedLines(BuildConfiguration.Release, 39, 39)
.AssertLinesCovered(BuildConfiguration.Debug, (41, 1), (44, 1), (45, 1), (46, 1))
.AssertLinesCovered(BuildConfiguration.Release, (45, 1));

}
else
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertLinesCovered(BuildConfiguration.Debug, (39, 1), (41, 1), (44, 1), (45, 1), (46, 1))
.AssertLinesCovered(BuildConfiguration.Release, (39, 1), (41, 1), (45, 1));
}
}
finally
{
File.Delete(path);
}
}
}
}
Loading