public static bool TryGetNext(IList<Instruction> sourceInstructions, int firstIndex, out InstructionGroup instructionGroup)
{
Contract.Requires(sourceInstructions != null);
if (firstIndex < 0 || firstIndex >= sourceInstructions.Count)
{
instructionGroup = null;
return false;
}
var instructions = new List<Instruction>();
var instruction = sourceInstructions[firstIndex];
instructions.Add(instruction);
int lastIndex;
if (instruction.OpCode.Code != Code.Ldarg_0) { lastIndex = firstIndex; }
else
{
int i;
// calls into base and chained constructors start like this
// so we'll look for the next call instruction or any instruction where the next instruction is another ldarg.0
// meaning that the stack was cleared at some point
// there is no assumption that this grouping is generally useful, but the hope is that it will catch constructor calls in this specific case
var isLastInstructionFound = false;
for (i = firstIndex + 1; !isLastInstructionFound && i < sourceInstructions.Count; i++)
{
instruction = sourceInstructions[i];
instructions.Add(instruction);
if (instruction.OpCode.Code == Code.Call ||
instruction.OpCode.Code == Code.Callvirt ||
instruction.OpCode.Code == Code.Calli ||
(instruction.Next != null && instruction.Next.OpCode.Code == Code.Ldarg_0))
{
isLastInstructionFound = true;
}
}
lastIndex = i - 1;
}
instructionGroup = new InstructionGroup(firstIndex, lastIndex, instructions);
return true;
}