I'm playing with mutation testing at the moment. One of the mutations I'm looking at involves swapping parameters, for which I may need to swap, for example Ldarg.0
and Ldarg_S
with an operand indicating the index.
The operand type for this is an inline arg, which in Mono.Cecil I believe requires me to create a properly instantiated ParameterDefinition
to store the 32-bit int index. Does anyone have enough experience with Cecil to point me in the right direction of an easy way to create an Instruction
instance with OpCode
of Ldarg_S
and an Operand
of the appropriate type?
You have two kinds of opcodes here, ldarg.0
, and ldarg
(and its _s) variant.
The first one is a “macro” opcode, meaning that it's used to reduce the size of the code for typically used values.
If you need to modify the parameters of a method, I suggest you firs transform all macro opcodes to a complete form, this is done using the SimplifyMacros()
extension method on MethodBody
from the helper library Mono.Cecil.Rocks:
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
// ..
method.Body.SimplifyMacros();
When this is done, an existing ldarg.0
instruction will now be ldarg
with the correct operand, which is as you guessed, a ParameterDefinition
.
With that in place, you can re-order the parameters, and create new instructions:
var il = method.Body.GetILProcessor();
var instruction = il.Create(OpCodes.Ldarg, aParameterDefinition);
il.InsertBefore(xxx, instruction);
When you're done, you can call the inverse of SimplifyMacros()
, OptimizeMacros()
, which will try to, well, optimize the opcodes into their macro form if possible.
One thing you'll have to take care of, is that the first argument of a instance method, the implicit “this”, is represented with the method.Body.ThisParameter
special parameter which you won't find in the .Parameters collection of the method.