using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using CollectionWeaver.Core; using CollectionWeaver.Extensions; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; using Mono.Collections.Generic; using MonoMod.Cil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CollectionWeaver")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+3e2b65ea5843d010d4d0ded79adad4982bc89e1b")] [assembly: AssemblyProduct("CollectionWeaver")] [assembly: AssemblyTitle("CollectionWeaver")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CollectionWeaver { public static class ListInterceptor { private static readonly ConcurrentDictionary> handlerCache = new ConcurrentDictionary>(); public static List> Handlers { get; private set; } = new List>(); public static void InvokeInsert(List list, int index, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Insert(list, index, value, fieldName); return; } try { list.Insert(index, value); } catch (Exception ex) { throw new Exception("Error in Insert for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeIndexOf(List list, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.IndexOf(list, value, fieldName); } try { return list.IndexOf(value); } catch (Exception ex) { throw new Exception("Error in IndexOf for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeRemoveAt(List list, int index, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.RemoveAt(list, index, fieldName); return; } try { list.RemoveAt(index); } catch (Exception ex) { throw new Exception("Error in RemoveAt for field '" + fieldName + "': " + ex.Message, ex); } } public static T InvokeGet_Item(List list, int index, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.GetItem(list, index, fieldName); } try { return list[index]; } catch (Exception ex) { throw new Exception("Error in Get_Item for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeSet_Item(List list, int index, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.SetItem(list, index, value, fieldName); return; } try { list[index] = value; } catch (Exception ex) { throw new Exception("Error in Set_Item for field '" + fieldName + "': " + ex.Message, ex); } } public static List.Enumerator InvokeGetEnumerator(List list, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.GetEnumerator(list, fieldName); } try { return list.GetEnumerator(); } catch (Exception ex) { throw new Exception("Error in GetEnumerator for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeAdd(List list, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Add(list, value, fieldName); return; } try { list.Add(value); } catch (Exception ex) { throw new Exception("Error in Add for field '" + fieldName + "': " + ex.Message, ex); } } public static bool InvokeRemove(List list, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.Remove(list, value, fieldName); } try { return list.Remove(value); } catch (Exception ex) { throw new Exception("Error in Remove for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeGet_Count(List list, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.Count(list, fieldName); } try { return list.Count; } catch (Exception ex) { throw new Exception("Error in Get_Count for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeClear(List list, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Clear(list, fieldName); return; } try { list.Clear(); } catch (Exception ex) { throw new Exception("Error in Clear for field '" + fieldName + "': " + ex.Message, ex); } } public static bool InvokeContains(List list, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.Contains(list, value, fieldName); } try { return list.Contains(value); } catch (Exception ex) { throw new Exception("Error in Contains for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeCopyTo(List list, T[] array, int arrayIndex, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.CopyTo(list, array, arrayIndex, fieldName); return; } try { list.CopyTo(array, arrayIndex); } catch (Exception ex) { throw new Exception("Error in CopyTo for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeAddRange(List list, IEnumerable values, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.AddRange(list, values, fieldName); return; } try { list.AddRange(values); } catch (Exception ex) { throw new Exception("Error in AddRange for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeInsertRange(List list, int index, IEnumerable values, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.InsertRange(list, index, values, fieldName); return; } try { list.InsertRange(index, values); } catch (Exception ex) { throw new Exception("Error in InsertRange for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeRemoveRange(List list, int index, int count, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.RemoveRange(list, index, count, fieldName); return; } try { list.RemoveRange(index, count); } catch (Exception ex) { throw new Exception("Error in RemoveRange for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeLastIndexOf(List list, T value, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.LastIndexOf(list, value, fieldName); } try { return list.LastIndexOf(value); } catch (Exception ex) { throw new Exception("Error in LastIndexOf for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeSort(List list, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Sort(list, fieldName); return; } try { list.Sort(); } catch (Exception ex) { throw new Exception("Error in Sort for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeSort(List list, Comparison comparison, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Sort(list, comparison, fieldName); return; } try { list.Sort(comparison); } catch (Exception ex) { throw new Exception("Error in Sort(Comparison) for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeSort(List list, IComparer comparer, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Sort(list, comparer, fieldName); return; } try { list.Sort(comparer); } catch (Exception ex) { throw new Exception("Error in Sort(IComparer) for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeReverse(List list, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Reverse(list, fieldName); return; } try { list.Reverse(); } catch (Exception ex) { throw new Exception("Error in Reverse for field '" + fieldName + "': " + ex.Message, ex); } } public static void InvokeReverse(List list, int index, int count, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { handler.Reverse(list, index, count, fieldName); return; } try { list.Reverse(index, count); } catch (Exception ex) { throw new Exception("Error in Reverse(int, int) for field '" + fieldName + "': " + ex.Message, ex); } } public static bool InvokeExists(List list, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.Exists(list, predicate, fieldName); } try { return list.Exists(predicate); } catch (Exception ex) { throw new Exception("Error in Exists for field '" + fieldName + "': " + ex.Message, ex); } } public static T InvokeFind(List list, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.Find(list, predicate, fieldName); } try { return list.Find(predicate); } catch (Exception ex) { throw new Exception("Error in Find for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeFindIndex(List list, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindIndex(list, predicate, fieldName); } try { return list.FindIndex(predicate); } catch (Exception ex) { throw new Exception("Error in FindIndex for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeFindIndex(List list, int index, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindIndex(list, index, predicate, fieldName); } try { return list.FindIndex(index, predicate); } catch (Exception ex) { throw new Exception("Error in FindIndex(int) for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeFindIndex(List list, int index, int count, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindIndex(list, index, count, predicate, fieldName); } try { return list.FindIndex(index, count, predicate); } catch (Exception ex) { throw new Exception("Error in FindIndex(int, int) for field '" + fieldName + "': " + ex.Message, ex); } } public static T InvokeFindLast(List list, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindLast(list, predicate, fieldName); } try { return list.FindLast(predicate); } catch (Exception ex) { throw new Exception("Error in FindLast for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeFindLastIndex(List list, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindLastIndex(list, predicate, fieldName); } try { return list.FindLastIndex(predicate); } catch (Exception ex) { throw new Exception("Error in FindLastIndex for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeFindLastIndex(List list, int index, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindLastIndex(list, index, predicate, fieldName); } try { return list.FindLastIndex(index, predicate); } catch (Exception ex) { throw new Exception("Error in FindLastIndex(int) for field '" + fieldName + "': " + ex.Message, ex); } } public static int InvokeFindLastIndex(List list, int index, int count, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.FindLastIndex(list, index, count, predicate, fieldName); } try { return list.FindLastIndex(index, count, predicate); } catch (Exception ex) { throw new Exception("Error in FindLastIndex(int, int) for field '" + fieldName + "': " + ex.Message, ex); } } public static bool InvokeTrueForAll(List list, Predicate predicate, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.TrueForAll(list, predicate, fieldName); } try { return list.TrueForAll(predicate); } catch (Exception ex) { throw new Exception("Error in TrueForAll for field '" + fieldName + "': " + ex.Message, ex); } } public static T[] InvokeToArray(List list, string fieldName) { ListInterceptorHandler handler = GetHandler(fieldName); if (handler != null) { return handler.ToArray(list, fieldName); } try { return list.ToArray(); } catch (Exception ex) { throw new Exception("Error in ToArray for field '" + fieldName + "': " + ex.Message, ex); } } private static ListInterceptorHandler? GetHandler(string fieldName) { return handlerCache.GetOrAdd(fieldName, delegate(string fn) { string fn2 = fn; return Handlers.FirstOrDefault((ListInterceptorHandler h) => h.ShouldHandleCall(fn2)); }); } } } namespace CollectionWeaver.IL { public class ILWeaver { private readonly WeaverOptions weaverOptions; private readonly MethodWeaver methodWeaver; public ILWeaver(WeaverOptions weaverOptions) { this.weaverOptions = weaverOptions; methodWeaver = new MethodWeaver(this.weaverOptions); } public WeaverResult Weave(AssemblyDefinition assembly) { ModuleDefinition mainModule = assembly.MainModule; WeaverResult weaverResult = new WeaverResult(); foreach (TypeDefinition item in from t in ModuleDefinitionRocks.GetAllTypes(mainModule) where t.IsClassType() select t) { foreach (MethodDefinition item2 in ((IEnumerable)item.Methods).Where((MethodDefinition m) => m.HasBody)) { weaverResult.Merge(methodWeaver.Weave(item2)); } } return weaverResult; } } public class MethodWeaver { [CompilerGenerated] private WeaverOptions P; private readonly NameResolver nameResolver; private readonly Dictionary interceptorTypeCache; private readonly Dictionary interceptorMethodRefCache; public MethodWeaver(WeaverOptions options) { P = options; nameResolver = new NameResolver(); interceptorTypeCache = new Dictionary(); interceptorMethodRefCache = new Dictionary(); base..ctor(); } public WeaverResult Weave(MethodDefinition method) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown MethodBodyRocks.SimplifyMacros(method.Body); ILContext val = new ILContext(method); try { ILCursor val2 = new ILCursor(val); WeaverResult weaverResult = new WeaverResult(); string scope = ((MemberReference)method.DeclaringType).Name + "." + ((MemberReference)method).Name; MethodReference targetMethodRef = null; while (val2.TryGotoNext((MoveType)0, new Func[1] { (Instruction instr) => ILPatternMatchingExt.MatchCallOrCallvirt(instr, ref targetMethodRef) })) { if (targetMethodRef == null || !((MemberReference)targetMethodRef).DeclaringType.IsSupportedCollectionType()) { continue; } GenericInstanceType genericInstanceType = ((MemberReference)targetMethodRef).DeclaringType.GetGenericInstanceType(); string name; if (genericInstanceType == null) { weaverResult.AddSkipped(scope, ((MemberReference)targetMethodRef).FullName, "Non-generic collection type"); } else if (!nameResolver.TryResolveName(val2.Clone(), ((IEnumerable)genericInstanceType.GenericArguments).ToArray(), out name)) { weaverResult.AddSkipped(scope, ((MemberReference)targetMethodRef).FullName, "Unresolvable name"); } else { if (!P.IsFieldIncluded(name)) { continue; } TypeDefinition interceptorTypeDef = GetInterceptorTypeDef(val2.Module, genericInstanceType); if (interceptorTypeDef == null) { weaverResult.AddSkipped(scope, name, "No interceptor found"); continue; } MethodReference interceptorMethodRef = GetInterceptorMethodRef(val2.Module, interceptorTypeDef, targetMethodRef, genericInstanceType); if (interceptorMethodRef == null) { weaverResult.AddSkipped(scope, name, "No matching interceptor method found"); continue; } PatchCollectionCall(val2, interceptorMethodRef, name); weaverResult.AddPatched(scope, name, (MethodReference)(object)method); } } MethodBodyRocks.OptimizeMacros(method.Body); return weaverResult; } finally { ((IDisposable)val)?.Dispose(); } } private void PatchCollectionCall(ILCursor cursor, MethodReference interceptorMethodRef, string declaredName) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) ILCursor cursor2 = cursor; List list = ((IEnumerable)cursor2.Method.Body.Instructions).Where((Instruction instr) => instr.Operand == cursor2.Next).ToList(); ILLabel val = cursor2.MarkLabel(); cursor2.Emit(OpCodes.Ldstr, declaredName).Remove().Emit(OpCodes.Call, interceptorMethodRef); foreach (Instruction item in list) { item.Operand = val.Target; } } private TypeDefinition? GetInterceptorTypeDef(ModuleDefinition module, GenericInstanceType collectionType) { if (!interceptorTypeCache.TryGetValue(((MemberReference)collectionType).FullName, out (GenericInstanceType, TypeDefinition) value)) { Type interceptorRuntimeType = GetInterceptorRuntimeType(collectionType); if ((object)interceptorRuntimeType == null) { return null; } GenericInstanceType obj = TypeReferenceRocks.MakeGenericInstanceType(module.ImportReference(interceptorRuntimeType), ((IEnumerable)collectionType.GenericArguments).ToArray()); TypeDefinition item = ((TypeReference)obj).Resolve(); value = (obj, item); interceptorTypeCache[((MemberReference)collectionType).FullName] = value; } return value.Item2; } private MethodReference? GetInterceptorMethodRef(ModuleDefinition module, TypeDefinition? interceptorTypeDef, MethodReference targetMethod, GenericInstanceType collectionType) { MethodReference targetMethod2 = targetMethod; GenericInstanceType collectionType2 = collectionType; MethodDefinition val = ((interceptorTypeDef != null) ? ((IEnumerable)interceptorTypeDef.Methods).FirstOrDefault((Func)((MethodDefinition m) => ((MemberReference)m).Name.EndsWith(((MemberReference)targetMethod2).Name, StringComparison.OrdinalIgnoreCase) && ((MethodReference)m).Parameters.Count - 2 == targetMethod2.Parameters.Count && ((IEnumerable)((MethodReference)m).Parameters).Skip(1).Take(((MethodReference)m).Parameters.Count - 2).Zip((IEnumerable)targetMethod2.Parameters, (ParameterDefinition interceptorParam, ParameterDefinition methodParam) => ((ParameterReference)interceptorParam).ParameterType.IsEquivalentTo(((ParameterReference)methodParam).ParameterType, collectionType2)) .All((bool match) => match))) : null); if (val == null) { return null; } string text = string.Join("|", ((IEnumerable)targetMethod2.Parameters).Select((ParameterDefinition p) => ((MemberReference)((ParameterReference)p).ParameterType).FullName)); string key = ((MemberReference)collectionType2).FullName + "::" + ((MemberReference)targetMethod2).Name + "::" + text; if (!interceptorMethodRefCache.TryGetValue(key, out MethodReference value)) { value = module.ImportReference((MethodReference)(object)val); ((MemberReference)value).DeclaringType = (TypeReference)(object)interceptorTypeCache[((MemberReference)collectionType2).FullName].Item1; interceptorMethodRefCache[key] = value; } return value; } private Type? GetInterceptorRuntimeType(GenericInstanceType? genericInstanceType) { string text = ((genericInstanceType != null) ? ((MemberReference)((TypeReference)genericInstanceType).GetElementType()).FullName : null); if (text == "System.Collections.Generic.List`1" || text == "System.Collections.Generic.IList`1") { return typeof(ListInterceptor<>); } return null; } } internal class NameResolver { internal bool TryResolveName(ILCursor cursor, TypeReference[] targetGenericArguments, out string name) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown ILCursor cursor2 = cursor; TypeReference[] targetGenericArguments2 = targetGenericArguments; string name2 = ((MemberReference)cursor2.Method).Name; Instruction next = cursor2.Next; name = $"{name2}_unk_{((next != null) ? next.Offset : 0)}"; if (cursor2.Next == null) { return false; } Instruction next2 = cursor2.Next; while (cursor2.TryGotoPrev((MoveType)2, new Func[1] { (Instruction instr) => instr.MatchCollectionLoad(cursor2.Method, targetGenericArguments2) })) { if (cursor2.Next == null) { return false; } int stackCount = 1; if (!TryTraceToTarget(cursor2.Next, next2, ref stackCount) || stackCount != 0) { continue; } if (cursor2.Previous.OpCode.IsFieldLoad()) { FieldReference val = (FieldReference)cursor2.Previous.Operand; name = ((MemberReference)((MemberReference)val).DeclaringType).Name + "." + ((MemberReference)val).Name; return true; } if (cursor2.Previous.OpCode.IsLdarg()) { name = $"{((MemberReference)cursor2.Method).Name}_arg{cursor2.Method.GetParameterIndex(cursor2.Previous)}"; return true; } while (cursor2.Previous.OpCode.IsLdloc() && cursor2.TryGotoPrev((MoveType)0, new Func[1] { (Instruction instr) => instr.IsComplimentaryStOf(cursor2.Previous) })) { if (cursor2.SkipNeutralBackward().Previous.OpCode.IsFieldLoad()) { FieldReference val2 = (FieldReference)cursor2.Previous.Operand; name = ((MemberReference)((MemberReference)val2).DeclaringType).Name + "." + ((MemberReference)val2).Name; return true; } if (cursor2.Previous.OpCode.IsLdarg()) { name = $"{((MemberReference)cursor2.Method).Name}_arg{cursor2.Method.GetParameterIndex(cursor2.Previous)}"; return true; } } } return false; } private bool TryTraceToTarget(Instruction current, Instruction target, ref int stackCount) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (current == null || target == null) { return false; } Instruction obj; for (; current != null; current = obj) { if (current == target) { stackCount -= current.GetStackPopCount(); return true; } stackCount -= current.GetStackPopCount(); stackCount += current.GetStackPushCount(); if (current.OpCode.IsUnconditionalBranch()) { object operand = current.Operand; Instruction val = (Instruction)((operand is Instruction) ? operand : null); if (val != null) { obj = val; continue; } } obj = current.Next; } return false; } } public class WeaverOptions { private readonly HashSet includedFieldNames = new HashSet(); public IReadOnlyCollection IncludedFieldNames => includedFieldNames; public WeaverOptions IncludeField(string fieldName) { includedFieldNames.Add(fieldName); return this; } internal bool IsFieldIncluded(string fieldName) { return includedFieldNames.Contains(fieldName); } } public class WeaverResult { private class Entry { public ResultKind Kind { get; set; } public string Scope { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public string Details { get; set; } = string.Empty; } private enum ResultKind { Patched, Skipped } private readonly List entries = new List(); public int PatchedCount => entries.Count((Entry e) => e.Kind == ResultKind.Patched); public int SkippedCount => entries.Count((Entry e) => e.Kind == ResultKind.Skipped); public void AddPatched(string scope, string name, MethodReference methodReference) { entries.Add(new Entry { Kind = ResultKind.Patched, Scope = scope, Name = name, Details = ((MemberReference)methodReference).FullName }); } public void AddSkipped(string scope, string name, string reason) { entries.Add(new Entry { Kind = ResultKind.Skipped, Scope = scope, Name = name, Details = reason }); } public void Merge(WeaverResult other) { if (other != null) { entries.AddRange(other.entries); } } public string CompileLog() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("=== Weaver Results ==="); foreach (Entry item in entries.Where((Entry e) => e.Kind == ResultKind.Patched)) { stringBuilder.AppendLine(" ✔ [" + item.Scope + "] " + item.Name + " -> " + item.Details); } List list = entries.Where((Entry e) => e.Kind == ResultKind.Skipped).ToList(); if (list.Count > 0) { stringBuilder.AppendLine("--- Skipped ---"); foreach (Entry item2 in list) { stringBuilder.AppendLine(" ✘ [" + item2.Scope + "] " + item2.Name + " -> " + item2.Details); } } return stringBuilder.ToString(); } } } namespace CollectionWeaver.Extensions { internal static class ArrayTypeExtensions { internal static bool IsEquivalentTo(this ArrayType source, ArrayType target, GenericInstanceType? genericContext) { if (((TypeSpecification)source).ElementType.IsEquivalentTo(((TypeSpecification)target).ElementType, genericContext)) { return source.Rank == target.Rank; } return false; } } internal static class CursorExtensions { internal static ILCursor SkipNeutralForward(this ILCursor cursor) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) while (cursor.Next != null && cursor.Next.OpCode.IsNeutral()) { cursor.GotoNext(Array.Empty>()); } return cursor; } internal static ILCursor SkipNeutralBackward(this ILCursor cursor) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) while (cursor.Previous != null && cursor.Previous.OpCode.IsNeutral()) { cursor.GotoPrev(Array.Empty>()); } return cursor; } } internal static class GenericInstanceTypeExtensions { internal static bool IsEquivalentTo(this GenericInstanceType source, GenericInstanceType target, GenericInstanceType? genericContext) { if (!((TypeSpecification)source).ElementType.IsEquivalentTo(((TypeSpecification)target).ElementType, genericContext)) { return false; } Collection genericArguments = source.GenericArguments; Collection genericArguments2 = target.GenericArguments; if (genericArguments.Count != genericArguments2.Count) { return false; } for (int i = 0; i < genericArguments.Count; i++) { if (!genericArguments[i].IsEquivalentTo(genericArguments2[i], genericContext)) { return false; } } return true; } } internal static class GenericParameterExtensions { internal static bool TryResolveAndMatch(this GenericParameter genericParam, TypeReference target, GenericInstanceType? genericContext) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) GenericParameter val = (GenericParameter)(object)((target is GenericParameter) ? target : null); if (val != null) { if (genericParam.Position == val.Position) { return genericParam.Type == val.Type; } return false; } if (genericContext != null && genericParam.Position < genericContext.GenericArguments.Count) { return ((MemberReference)genericContext.GenericArguments[genericParam.Position]).FullName == ((MemberReference)target).FullName; } return false; } } internal static class InstructionExtensions { internal static bool MatchCollectionLoad(this Instruction instruction, MethodDefinition method, TypeReference[] targetGenericArguments) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected I4, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 if (!instruction.OpCode.IsLoadCode()) { return false; } OpCode opCode = instruction.OpCode; Code code = ((OpCode)(ref opCode)).Code; if ((int)code <= 120) { switch (code - 2) { case 4: goto IL_0099; case 5: goto IL_00ab; case 6: goto IL_00bd; case 7: goto IL_00cf; case 15: goto IL_00e1; case 0: goto IL_00fe; case 1: goto IL_011b; case 2: goto IL_0136; case 3: goto IL_0151; case 13: goto IL_016c; case 8: case 9: case 10: case 11: case 12: case 14: goto IL_01a0; } if ((int)code == 120) { goto IL_0186; } } else { if ((int)code == 123) { goto IL_0186; } if ((int)code == 199) { goto IL_016c; } if ((int)code == 202) { goto IL_00e1; } } goto IL_01a0; IL_0186: object operand = instruction.Operand; object obj = ((operand is FieldReference) ? operand : null); TypeReference val = ((obj != null) ? ((FieldReference)obj).FieldType : null); goto IL_01a2; IL_01a0: val = null; goto IL_01a2; IL_00e1: object operand2 = instruction.Operand; object obj2 = ((operand2 is VariableReference) ? operand2 : null); val = ((obj2 != null) ? ((VariableReference)obj2).VariableType : null); goto IL_01a2; IL_01a2: TypeReference val2 = val; if (val2 == null || !val2.IsSupportedCollectionType()) { return false; } GenericInstanceType genericInstanceType = val2.GetGenericInstanceType(); if (genericInstanceType != null) { return targetGenericArguments.Select((TypeReference x) => ((MemberReference)x).FullName).SequenceEqual(((IEnumerable)genericInstanceType.GenericArguments).Select((TypeReference x) => ((MemberReference)x).FullName)); } return false; IL_00cf: val = method.Body.GetVariableType(3); goto IL_01a2; IL_00bd: val = method.Body.GetVariableType(2); goto IL_01a2; IL_00ab: val = method.Body.GetVariableType(1); goto IL_01a2; IL_0099: val = method.Body.GetVariableType(0); goto IL_01a2; IL_0151: val = (((MethodReference)method).HasThis ? method.GetParameterType(2) : method.GetParameterType(3)); goto IL_01a2; IL_011b: val = (((MethodReference)method).HasThis ? method.GetParameterType(0) : method.GetParameterType(1)); goto IL_01a2; IL_00fe: val = (TypeReference)(((MethodReference)method).HasThis ? ((object)method.DeclaringType) : ((object)method.GetParameterType(0))); goto IL_01a2; IL_016c: object operand3 = instruction.Operand; object obj3 = ((operand3 is ParameterReference) ? operand3 : null); val = ((obj3 != null) ? ((ParameterReference)obj3).ParameterType : null); goto IL_01a2; IL_0136: val = (((MethodReference)method).HasThis ? method.GetParameterType(1) : method.GetParameterType(2)); goto IL_01a2; } internal static bool IsComplimentaryStOf(this Instruction stInstruction, Instruction ldInstruction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!stInstruction.OpCode.IsStloc() || !ldInstruction.OpCode.IsLdloc()) { return false; } int? localCodeIndex = stInstruction.GetLocalCodeIndex(); int? localCodeIndex2 = ldInstruction.GetLocalCodeIndex(); if (localCodeIndex.HasValue) { return localCodeIndex == localCodeIndex2; } return false; } internal static int? GetLocalCodeIndex(this Instruction instr) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 OpCode opCode = instr.OpCode; Code code = ((OpCode)(ref opCode)).Code; switch (code - 6) { default: if ((int)code != 202 && (int)code != 204) { break; } goto case 11; case 0: case 4: return 0; case 1: case 5: return 1; case 2: case 6: return 2; case 3: case 7: return 3; case 11: case 13: { object operand = instr.Operand; VariableReference val = (VariableReference)((operand is VariableReference) ? operand : null); return (val != null) ? new int?(val.Index) : null; } case 8: case 9: case 10: case 12: break; } return null; } internal static int GetStackPopCount(this Instruction inst) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected I4, but got Unknown OpCode opCode = inst.OpCode; StackBehaviour stackBehaviourPop = ((OpCode)(ref opCode)).StackBehaviourPop; return (int)stackBehaviourPop switch { 0 => 0, 1 => 1, 2 => 2, 3 => 1, 4 => 2, 5 => 2, 6 => 2, 7 => 3, 8 => 2, 9 => 2, 10 => 1, 11 => 2, 12 => 2, 13 => 3, 14 => 3, 15 => 3, 16 => 3, 17 => 3, 27 => inst.GetVarPop(), _ => 0, }; } internal static int GetStackPushCount(this Instruction inst) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected I4, but got Unknown OpCode opCode = inst.OpCode; StackBehaviour stackBehaviourPush = ((OpCode)(ref opCode)).StackBehaviourPush; return (stackBehaviourPush - 19) switch { 0 => 0, 1 => 1, 2 => 2, 3 => 1, 4 => 1, 5 => 1, 6 => 1, 7 => 1, 9 => inst.GetVarPush(), _ => 0, }; } internal static int GetVarPop(this Instruction inst) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 OpCode opCode = inst.OpCode; if ((int)((OpCode)(ref opCode)).FlowControl == 2) { object operand = inst.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val != null) { return val.Parameters.Count + (val.HasThis ? 1 : 0); } } opCode = inst.OpCode; return ((int)((OpCode)(ref opCode)).Code == 68) ? 1 : 0; } internal static int GetVarPush(this Instruction inst) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 OpCode opCode = inst.OpCode; if ((int)((OpCode)(ref opCode)).FlowControl == 2) { object operand = inst.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val != null) { return ((int)val.ReturnType.MetadataType != 1) ? 1 : 0; } } return 0; } } internal static class MethodBodyExtensions { internal static TypeReference? GetVariableType(this MethodBody body, int index) { if (index < 0 || index >= body.Variables.Count) { return null; } return ((VariableReference)body.Variables[index]).VariableType; } } internal static class MethodDefinitionExtensions { internal static TypeReference? GetParameterType(this MethodDefinition method, int index) { if (index < 0 || index >= ((MethodReference)method).Parameters.Count) { return null; } return ((ParameterReference)((MethodReference)method).Parameters[index]).ParameterType; } internal static int? GetParameterIndex(this MethodDefinition method, Instruction instr) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected I4, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 OpCode opCode = instr.OpCode; Code code = ((OpCode)(ref opCode)).Code; switch (code - 2) { default: if ((int)code == 14 || (int)code == 199) { object operand = instr.Operand; ParameterReference val = (ParameterReference)((operand is ParameterReference) ? operand : null); return (val != null) ? new int?(val.Index) : null; } return null; case 0: return (!((MethodReference)method).HasThis) ? 1 : 0; case 1: return ((MethodReference)method).HasThis ? 1 : 2; case 2: return ((MethodReference)method).HasThis ? 2 : 3; case 3: return ((MethodReference)method).HasThis ? 3 : 4; } } } internal static class OpCodeExtensions { internal static bool IsLoadCode(this OpCode opCode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!opCode.IsLdloc() && !opCode.IsLdarg() && !opCode.IsLdc() && !opCode.IsLdelem() && !opCode.IsFieldLoad() && !opCode.IsLdNullOrStr()) { return opCode.IsLdind(); } return true; } internal static bool IsFieldLoad(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if ((int)code == 120 || (int)code == 123) { return true; } return false; } internal static bool IsLdloc(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 6 <= 3 || (int)code == 17 || (int)code == 202) { return true; } return false; } internal static bool IsLdarg(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 2 <= 3 || code - 14 <= 1 || code - 199 <= 1) { return true; } return false; } internal static bool IsLdc(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 21 <= 14) { return true; } return false; } internal static bool IsLdelem(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if ((int)code == 145 || (int)code == 151 || (int)code == 160) { return true; } return false; } internal static bool IsLdind(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 69 <= 6 || code - 77 <= 2) { return true; } return false; } internal static bool IsLdNullOrStr(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if ((int)code == 20 || (int)code == 113) { return true; } return false; } internal static bool IsStloc(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 10 <= 3 || (int)code == 19 || (int)code == 204) { return true; } return false; } internal static bool IsNeutral(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if ((int)code <= 209) { if ((int)code == 0 || code - 207 <= 2) { goto IL_002f; } } else if ((int)code == 211 || (int)code == 218) { goto IL_002f; } return false; IL_002f: return true; } internal static bool IsUnconditionalBranch(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if ((int)code == 42 || (int)code == 55 || code - 187 <= 1) { return true; } return false; } internal static bool IsConditionalBranch(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 43 <= 1 || code - 56 <= 1) { return true; } return false; } internal static bool IsCompareBranch(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 Code code = ((OpCode)(ref opCode)).Code; if (code - 45 <= 9 || code - 58 <= 9) { return true; } return false; } internal static bool IsSwitchBranch(this OpCode opCode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 return (int)((OpCode)(ref opCode)).Code == 68; } } internal static class TypeDefinitionExtensions { internal static bool IsClassType(this TypeDefinition typeDef) { if (typeDef.IsClass && !typeDef.IsInterface) { return !((TypeReference)typeDef).IsValueType; } return false; } } internal static class TypeReferenceExtensions { private static readonly Dictionary collectionTypeCache = new Dictionary(); private static readonly Dictionary genericInstanceCache = new Dictionary(); internal static bool IsSupportedCollectionType(this TypeReference typeRef) { return typeRef.IsListType(); } internal static bool IsListType(this TypeReference typeRef) { if (!collectionTypeCache.TryGetValue(((MemberReference)typeRef).FullName, out var value)) { bool flag = typeRef.Namespace == "System.Collections.Generic"; if (flag) { string name = ((MemberReference)typeRef).Name; bool flag2 = ((name == "List`1" || name == "IList`1") ? true : false); flag = flag2; } if (flag && typeRef is GenericInstanceType) { value = true; } else { TypeDefinition obj = typeRef.Resolve(); value = ((obj == null) ? null : obj.BaseType?.IsListType()).GetValueOrDefault(); } collectionTypeCache[((MemberReference)typeRef).FullName] = value; } return value; } internal static GenericInstanceType? GetGenericInstanceType(this TypeReference typeRef) { if (!genericInstanceCache.TryGetValue(((MemberReference)typeRef).FullName, out GenericInstanceType value)) { try { GenericInstanceType val = (GenericInstanceType)(object)((typeRef is GenericInstanceType) ? typeRef : null); value = (GenericInstanceType)((val == null) ? ((object)typeRef.Resolve().BaseType?.GetGenericInstanceType()) : ((object)val)); genericInstanceCache[((MemberReference)typeRef).FullName] = value; } catch (Exception ex) { Log.Debug("Failed to resolve generic instance type for " + ((MemberReference)typeRef).FullName + ": " + ex.Message); genericInstanceCache[((MemberReference)typeRef).FullName] = null; } } return value; } internal static bool IsEquivalentTo(this TypeReference source, TypeReference target, GenericInstanceType? genericContext = null) { if (source == null || target == null) { return false; } if (((MemberReference)source).FullName == ((MemberReference)target).FullName) { return true; } GenericParameter val = (GenericParameter)(object)((source is GenericParameter) ? source : null); if (val != null) { return val.TryResolveAndMatch(target, genericContext); } GenericParameter val2 = (GenericParameter)(object)((target is GenericParameter) ? target : null); if (val2 != null) { return val2.TryResolveAndMatch(source, genericContext); } GenericInstanceType val3 = (GenericInstanceType)(object)((source is GenericInstanceType) ? source : null); if (val3 != null) { GenericInstanceType val4 = (GenericInstanceType)(object)((target is GenericInstanceType) ? target : null); if (val4 != null) { return val3.IsEquivalentTo(val4, genericContext); } } ArrayType val5 = (ArrayType)(object)((source is ArrayType) ? source : null); if (val5 != null) { ArrayType val6 = (ArrayType)(object)((target is ArrayType) ? target : null); if (val6 != null) { return val5.IsEquivalentTo(val6, genericContext); } } return false; } } } namespace CollectionWeaver.Core { public class ConsoleLogger : ILogger { private readonly object logLock = new object(); public void Log(LogLevel logLevel, string message) { lock (logLock) { ConsoleColor foregroundColor = Console.ForegroundColor; try { Console.ForegroundColor = GetLevelColor(logLevel); Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [{logLevel}] {message}"); } finally { Console.ForegroundColor = foregroundColor; } } } private ConsoleColor GetLevelColor(LogLevel level) { return level switch { LogLevel.Debug => ConsoleColor.DarkGray, LogLevel.Info => ConsoleColor.White, LogLevel.Warning => ConsoleColor.Yellow, LogLevel.Error => ConsoleColor.Red, _ => ConsoleColor.Gray, }; } } public interface ILogger { void Log(LogLevel logLevel, string message); } [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class InterceptorHandler : Attribute { } public static class InterceptorRegistry { public static void RegisterFromAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } foreach (Type item in assembly.GetTypes().Where(IsInterceptorType)) { TryRegisterHandler(item); } } public static void RegisterFromAllAssemblies() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { RegisterFromAssembly(assembly); } catch (Exception ex) { Log.Debug("Skipping assembly " + assembly.GetName().Name + ": " + ex.Message); } } } private static bool IsInterceptorType(Type type) { if (type.IsClass && !type.IsAbstract) { return type.GetCustomAttribute() != null; } return false; } private static void TryRegisterHandler(Type handlerType) { Type type = FindInterceptorBase(handlerType); if (type == null) { Log.Warning(handlerType.Name + " has [Interceptor] but does not inherit from a valid InterceptorHandler"); return; } Type type2 = ResolveInterceptorType(type); if (type2 == null) { Log.Warning("No runtime interceptor found for " + type.Name); return; } IList handlersList = GetHandlersList(type2); if (handlersList == null) { Log.Error("Cannot access Handlers property on " + type2.Name); } else { RegisterHandler(handlersList, handlerType, type.GenericTypeArguments); } } private static Type? FindInterceptorBase(Type type) { Type baseType = type.BaseType; while (baseType != null) { if (baseType.IsGenericType && baseType.Name.EndsWith("InterceptorHandler`1")) { return baseType; } baseType = baseType.BaseType; } return null; } private static Type? ResolveInterceptorType(Type interceptorBase) { return ((!(interceptorBase.Name == "ListInterceptorHandler`1")) ? null : typeof(ListInterceptor<>))?.MakeGenericType(interceptorBase.GenericTypeArguments); } private static IList? GetHandlersList(Type interceptorType) { return interceptorType.GetProperty("Handlers", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) as IList; } private static void RegisterHandler(IList handlerList, Type handlerType, Type[] genericArgs) { try { object obj = Activator.CreateInstance(handlerType); if (obj == null) { Log.Error("Activator.CreateInstance returned null for " + handlerType.Name); return; } handlerList.Add(obj); Log.Info("Registered " + handlerType.Name + " for " + string.Join(", ", genericArgs.Select((Type a) => a.Name))); } catch (Exception ex) { Log.Error("Failed to register " + handlerType.Name + ": " + ex.Message); } } } public abstract class ListInterceptorHandler { public abstract bool ShouldHandleCall(string fieldName); public virtual T GetItem(List list, int index, string fieldName) { return list[index]; } public virtual void SetItem(List list, int index, T value, string fieldName) { list[index] = value; } public virtual int Count(List list, string fieldName) { return list.Count; } public virtual List.Enumerator GetEnumerator(List list, string fieldName) { return list.GetEnumerator(); } public virtual void Add(List list, T item, string fieldName) { list.Add(item); } public virtual void Insert(List list, int index, T value, string fieldName) { list.Insert(index, value); } public virtual void AddRange(List list, IEnumerable values, string fieldName) { list.AddRange(values); } public virtual bool Remove(List list, T value, string fieldName) { return list.Remove(value); } public virtual void RemoveRange(List list, int index, int count, string fieldName) { list.RemoveRange(index, count); } public virtual void Clear(List list, string fieldName) { list.Clear(); } public virtual bool Contains(List list, T value, string fieldName) { return list.Contains(value); } public virtual int IndexOf(List list, T value, string fieldName) { return list.IndexOf(value); } public virtual void Sort(List list, string fieldName) { list.Sort(); } public virtual void Sort(List list, Comparison comparison, string fieldName) { list.Sort(comparison); } public virtual void Sort(List list, IComparer comparer, string fieldName) { list.Sort(comparer); } public virtual void Reverse(List list, string fieldName) { list.Reverse(); } public virtual void Reverse(List list, int index, int count, string fieldName) { list.Reverse(index, count); } public virtual void CopyTo(List list, T[] array, int arrayIndex, string fieldName) { list.CopyTo(array, arrayIndex); } public virtual void RemoveAt(List list, int index, string fieldName) { list.RemoveAt(index); } public virtual void InsertRange(List list, int index, IEnumerable values, string fieldName) { list.InsertRange(index, values); } public virtual int LastIndexOf(List list, T value, string fieldName) { return list.LastIndexOf(value); } public virtual bool Exists(List list, Predicate predicate, string fieldName) { return list.Exists(predicate); } public virtual T Find(List list, Predicate predicate, string fieldName) { return list.Find(predicate); } public virtual int FindIndex(List list, Predicate predicate, string fieldName) { return list.FindIndex(predicate); } public virtual int FindIndex(List list, int index, Predicate predicate, string fieldName) { return list.FindIndex(index, predicate); } public virtual int FindIndex(List list, int index, int count, Predicate predicate, string fieldName) { return list.FindIndex(index, count, predicate); } public virtual T FindLast(List list, Predicate predicate, string fieldName) { return list.FindLast(predicate); } public virtual int FindLastIndex(List list, Predicate predicate, string fieldName) { return list.FindLastIndex(predicate); } public virtual int FindLastIndex(List list, int index, Predicate predicate, string fieldName) { return list.FindLastIndex(index, predicate); } public virtual int FindLastIndex(List list, int index, int count, Predicate predicate, string fieldName) { return list.FindLastIndex(index, count, predicate); } public virtual bool TrueForAll(List list, Predicate predicate, string fieldName) { return list.TrueForAll(predicate); } public virtual T[] ToArray(List list, string fieldName) { return list.ToArray(); } } public static class Log { public static ILogger Logger { get; set; } = new ConsoleLogger(); public static LogLevel LogLevel { get; set; } = LogLevel.Debug; internal static void Debug(string message) { InternalLog(LogLevel.Debug, message); } internal static void Info(string message) { InternalLog(LogLevel.Info, message); } internal static void Warning(string message) { InternalLog(LogLevel.Warning, message); } internal static void Error(string message) { InternalLog(LogLevel.Error, message); } private static void InternalLog(LogLevel logLevel, string message) { if (logLevel >= LogLevel) { Logger.Log(logLevel, message); } } } public enum LogLevel { Debug, Info, Warning, Error, None } }