private void RemoveObsoleteCodeForArgumentExpression(MethodDefinition method, Collection<Instruction> instructions, TypeDefinition displayClassType)
{
// Display class is used when there are still calls to load a field from the display class
if (instructions.UsesType(displayClassType, OpCodes.Ldfld, OpCodes.Ldftn))
{
return;
}
FodyEnvironment.LogDebug($"Method '{method.GetFullName()}' no longer uses display class '{displayClassType.GetFullName()}', removing the display class from the method");
// Remove display class from container
if (method.DeclaringType.NestedTypes.Contains(displayClassType))
{
method.DeclaringType.NestedTypes.Remove(displayClassType);
}
// Remove display class - variables
for (var i = 0; i < method.Body.Variables.Count; i++)
{
var variable = method.Body.Variables[i];
if (string.Equals(variable.VariableType.Name, displayClassType.Name))
{
method.Body.Variables.RemoveAt(i--);
}
}
// Remove display class creation, can be either:
//
// Msbuild
// L_0000: newobj instance void Catel.Fody.TestAssembly.ArgumentChecksAsExpressionsClass/<>c__DisplayClass1a::.ctor()
// L_0005: stloc.0
//
// Roslyn
// L_0000: newobj instance void Catel.Fody.TestAssembly.ArgumentChecksAsExpressionsClass/<>c__DisplayClass1a::.ctor()
// L_0005: dup
for (var i = 0; i < instructions.Count; i++)
{
var innerInstruction = instructions[i];
if (innerInstruction.OpCode == OpCodes.Newobj)
{
var remove = false;
var methodReference = innerInstruction.Operand as MethodReference;
if (methodReference != null)
{
if (string.Equals(methodReference.DeclaringType.Name, displayClassType.Name))
{
remove = true;
}
}
var methodDefinition = innerInstruction.Operand as MethodDefinition;
if (methodDefinition != null)
{
if (string.Equals(methodDefinition.DeclaringType.Name, displayClassType.Name))
{
remove = true;
}
}
if (remove)
{
// Delete 2 instructions, same location since remove will move everything 1 place up
instructions.RemoveAt(i);
// Special case in .net core
if (instructions[i].OpCode == OpCodes.Dup)
{
instructions.RemoveAt(i);
}
instructions.RemoveAt(i);
}
}
}
//// Remove all assignments to the display class
//// ldarg.0
//// stfld class MyClass/<>c__DisplayClass0_0`1<!!T>::myArgument
//for (var i = 0; i < instructions.Count; i++)
//{
// var innerInstruction = instructions[i];
//}
// Remove display class allocation and assigments
// L_0014: ldloc.0 (can also be dup)
// L_0015: ldarg.3
// L_0016: stfld object Catel.Fody.TestAssembly.ArgumentChecksAsExpressionsClass/<>c__DisplayClass28::myObject3
for (var i = 0; i < instructions.Count; i++)
{
var innerInstruction = instructions[i];
if (innerInstruction.UsesType(displayClassType, OpCodes.Stfld))
{
// Remove the stfld + 2 previous operations
instructions.RemoveAt(i);
instructions.RemoveAt(i - 1);
instructions.RemoveAt(i - 2);
i -= 3;
}
}
// Remove duplicate nop instructions at the start of a method
if (instructions.Count > 0)
{
var startInstruction = instructions[0];
if (startInstruction.IsOpCode(OpCodes.Nop))
{
instructions.RemoveAt(0);
}
}
}