예제 #1
0
        private static void ProcessEachInstruction(ModuleDefinition systemModuleDefinition, Instruction loadTokenInstruction, ScopedProcessor processor, ModuleDefinition moduleDefinition)
        {
            if (!IsValidLoadTokenInstruction(loadTokenInstruction, out var enumTypeReference) || !enumTypeReference.TryToDefinition(out var enumTypeDefinition) || !enumTypeDefinition.IsEnum)
            {
                return;
            }
            var getTypeFromHandleInstruction = loadTokenInstruction.Next;

            if (getTypeFromHandleInstruction is null || getTypeFromHandleInstruction.OpCode.Code != Code.Call || !(getTypeFromHandleInstruction.Operand is MethodReference getTypeFromHandleMethodReference) || getTypeFromHandleMethodReference.FullName != "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)")
            {
                return;
            }
            var getValuesInstruction = getTypeFromHandleInstruction.Next;

            if (getValuesInstruction is null || getValuesInstruction.OpCode != OpCodes.Call || !(getValuesInstruction.Operand is MethodReference methodReference) || methodReference.FullName != "System.Array System.Enum::GetValues(System.Type)")
            {
                return;
            }
            var castClassOrIsInstInstruction = getValuesInstruction.Next;
            var enumsGetValuesInstructions   = moduleDefinition.EnumGetValuesInstructions(enumTypeDefinition, systemModuleDefinition);

            if (!(castClassOrIsInstInstruction is null) && (castClassOrIsInstInstruction.OpCode == OpCodes.Isinst || castClassOrIsInstInstruction.OpCode == OpCodes.Castclass))
            {
                var castTargetClass = (TypeReference)castClassOrIsInstInstruction.Operand;
                switch (enumsGetValuesInstructions.Length)
                {
                case 0: return;

                case 1:
                    processor
                    .Replace(loadTokenInstruction, enumsGetValuesInstructions[0])
                    .Remove(getTypeFromHandleInstruction)
                    .Remove(getValuesInstruction);
                    if (castTargetClass.GetElementType().FullName == enumTypeDefinition.FullName)
                    {
                        processor.Remove(castClassOrIsInstInstruction);
                    }
                    break;

                case 2:
                    processor
                    .Replace(loadTokenInstruction, enumsGetValuesInstructions[0])
                    .Replace(getTypeFromHandleInstruction, enumsGetValuesInstructions[1])
                    .Remove(getValuesInstruction);
                    if (castTargetClass.GetElementType().FullName == enumTypeDefinition.FullName)
                    {
                        processor.Remove(castClassOrIsInstInstruction);
                    }
                    break;

                case 3:
                    processor
                    .Replace(loadTokenInstruction, enumsGetValuesInstructions[0])
                    .Replace(getTypeFromHandleInstruction, enumsGetValuesInstructions[1])
                    .Replace(getValuesInstruction, enumsGetValuesInstructions[2]);
                    if (castTargetClass.GetElementType().FullName == enumTypeDefinition.FullName)
                    {
                        processor.Remove(castClassOrIsInstInstruction);
                    }
                    break;

                default:
                    processor
                    .Replace(loadTokenInstruction, enumsGetValuesInstructions[0])
                    .Replace(getTypeFromHandleInstruction, enumsGetValuesInstructions[1])
                    .Replace(getValuesInstruction, enumsGetValuesInstructions[2]);
                    if (castTargetClass.GetElementType().FullName == enumTypeDefinition.FullName)
                    {
                        processor.Replace(castClassOrIsInstInstruction, enumsGetValuesInstructions[3]);
                        for (var i = 4; i < enumsGetValuesInstructions.Length; i++)
                        {
                            processor.InsertAfter(enumsGetValuesInstructions[i - 1], enumsGetValuesInstructions[i]);
                        }
                    }
                    else
                    {
                        for (var i = 3; i < enumsGetValuesInstructions.Length; i++)
                        {
                            processor.InsertAfter(enumsGetValuesInstructions[i - 1], enumsGetValuesInstructions[i]);
                        }
                    }
                    break;
                }
            }