From b9206db8abbe670f88e1fbe4a71f0986765f05ff Mon Sep 17 00:00:00 2001 From: Andreas Pardeike Date: Sat, 17 Jun 2023 18:04:30 +0200 Subject: [PATCH] cleans up conditional compiles; tries to fix #533; refactors CodeMatch; adds IEnumerable.Matches() --- Harmony/Extras/DelegateTypeFactory.cs | 2 +- .../ForwardingAttributes/Mono.Cecil.Cil.cs | 2 +- .../ForwardingAttributes/Mono.Cecil.Mdb.cs | 2 +- .../ForwardingAttributes/Mono.Cecil.Pdb.cs | 2 +- .../ForwardingAttributes/Mono.Cecil.Rocks.cs | 2 +- Harmony/ForwardingAttributes/Mono.Cecil.cs | 2 +- .../Mono.Collections.Generic.cs | 2 +- .../Mono.CompilerServices.SymbolWriter.cs | 2 +- .../ForwardingAttributes/MonoMod.Utils.Cil.cs | 2 +- Harmony/ForwardingAttributes/MonoMod.Utils.cs | 2 +- Harmony/Harmony.csproj | 4 - Harmony/Internal/Emitter.cs | 3 - Harmony/Internal/PatchTools.cs | 4 +- Harmony/Public/Attributes.cs | 2 +- Harmony/Public/Harmony.cs | 4 +- Harmony/Public/Patch.cs | 26 ++-- Harmony/Public/PatchJsonConverter.cs | 2 +- Harmony/Tools/AccessTools.cs | 4 +- Harmony/Tools/CodeMatch.cs | 125 ++++++------------ Harmony/Tools/Extensions.cs | 70 ++++++++-- HarmonyTests/Extras/PatchSerialization.cs | 2 +- HarmonyTests/HarmonyTests.csproj | 4 - HarmonyTests/IL/TestMethodBodyReader.cs | 2 +- HarmonyTests/Patching/Assets/PatchClasses.cs | 9 -- HarmonyTests/Tools/TestCodeMatcher.cs | 5 +- HarmonyTests/Traverse/TestTraverse_Types.cs | 2 +- 26 files changed, 136 insertions(+), 152 deletions(-) diff --git a/Harmony/Extras/DelegateTypeFactory.cs b/Harmony/Extras/DelegateTypeFactory.cs index 04df458c..1f8679a3 100644 --- a/Harmony/Extras/DelegateTypeFactory.cs +++ b/Harmony/Extras/DelegateTypeFactory.cs @@ -44,7 +44,7 @@ public Type CreateDelegateType(MethodInfo method) for (var i = 0; i < parameters.Length; i++) invokeMethod.DefineParameter(i + 1, ParameterAttributes.None, parameters[i].Name); -#if NETSTANDARD2_0 +#if NETSTANDARD return typeBuilder.CreateTypeInfo().AsType(); #else return typeBuilder.CreateType(); diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs index 9633dfa2..23b2e22e 100644 --- a/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Cil.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.Cecil.Cil.Code))] diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs index f1b5a9ef..24a23087 100644 --- a/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Mdb.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.Cecil.Mdb.MdbReader))] diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs index f1a97474..87ddb933 100644 --- a/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Pdb.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.Cecil.Pdb.NativePdbReader))] diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs b/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs index 6b1f49b7..f280f013 100644 --- a/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs +++ b/Harmony/ForwardingAttributes/Mono.Cecil.Rocks.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.Cecil.Rocks.IILVisitor))] diff --git a/Harmony/ForwardingAttributes/Mono.Cecil.cs b/Harmony/ForwardingAttributes/Mono.Cecil.cs index d47a995c..bc59c59f 100644 --- a/Harmony/ForwardingAttributes/Mono.Cecil.cs +++ b/Harmony/ForwardingAttributes/Mono.Cecil.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.Cecil.AssemblyAttributes))] diff --git a/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs b/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs index f4e63491..ee777f6d 100644 --- a/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs +++ b/Harmony/ForwardingAttributes/Mono.Collections.Generic.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.Collections.Generic.Collection<>))] diff --git a/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs b/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs index 41936421..6c334824 100644 --- a/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs +++ b/Harmony/ForwardingAttributes/Mono.CompilerServices.SymbolWriter.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Mono.CompilerServices.SymbolWriter.AnonymousScopeEntry))] diff --git a/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs b/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs index 1df2a7e3..cd4aaf58 100644 --- a/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs +++ b/Harmony/ForwardingAttributes/MonoMod.Utils.Cil.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(MonoMod.Utils.Cil.CecilILGenerator))] diff --git a/Harmony/ForwardingAttributes/MonoMod.Utils.cs b/Harmony/ForwardingAttributes/MonoMod.Utils.cs index 11755aff..ca6a4a1c 100644 --- a/Harmony/ForwardingAttributes/MonoMod.Utils.cs +++ b/Harmony/ForwardingAttributes/MonoMod.Utils.cs @@ -1,4 +1,4 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(MonoMod.Utils.DMDEmitDynamicMethodGenerator))] diff --git a/Harmony/Harmony.csproj b/Harmony/Harmony.csproj index c2098c80..35e9b537 100644 --- a/Harmony/Harmony.csproj +++ b/Harmony/Harmony.csproj @@ -84,10 +84,6 @@ false - - $(DefineConstants);NET50_OR_GREATER - - diff --git a/Harmony/Internal/Emitter.cs b/Harmony/Internal/Emitter.cs index b626e7ce..4221e2c9 100644 --- a/Harmony/Internal/Emitter.cs +++ b/Harmony/Internal/Emitter.cs @@ -356,8 +356,6 @@ internal void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalPara il.EmitCall(opcode, methodInfo, optionalParameterTypes); } -#if NETSTANDARD2_0 || NETCOREAPP2_0 -#else internal void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes) { instructions.Add(CurrentPos(), new CodeInstruction(opcode, unmanagedCallConv)); @@ -365,7 +363,6 @@ internal void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type LogIL(opcode, unmanagedCallConv, extra); il.EmitCalli(opcode, unmanagedCallConv, returnType, parameterTypes); } -#endif internal void EmitCalli(OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes) { diff --git a/Harmony/Internal/PatchTools.cs b/Harmony/Internal/PatchTools.cs index ad5a8927..1f023f19 100644 --- a/Harmony/Internal/PatchTools.cs +++ b/Harmony/Internal/PatchTools.cs @@ -52,7 +52,7 @@ internal static MethodInfo GetPatchMethod(Type patchType, string attributeName) internal static AssemblyBuilder DefineDynamicAssembly(string name) { var assemblyName = new AssemblyName(name); -#if NETCOREAPP2_0 || NETCOREAPP3_0 || NETCOREAPP3_1 || NETSTANDARD2_0 || NET50_OR_GREATER +#if NETCOREAPP || NETSTANDARD || NET5_0_OR_GREATER return AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); #else return AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); @@ -102,7 +102,7 @@ internal static MethodBase GetOriginalMethod(this HarmonyMethod attr) var enumMethod = AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes); return AccessTools.EnumeratorMoveNext(enumMethod); -#if NET45_OR_GREATER +#if NET45_OR_GREATER || NETSTANDARD || NETCOREAPP case MethodType.Async: if (attr.methodName is null) return null; diff --git a/Harmony/Public/Attributes.cs b/Harmony/Public/Attributes.cs index edd077ac..55dda224 100644 --- a/Harmony/Public/Attributes.cs +++ b/Harmony/Public/Attributes.cs @@ -19,7 +19,7 @@ public enum MethodType StaticConstructor, /// This targets the MoveNext method of the enumerator result, that actually contains the method's implementation Enumerator, -#if NET45_OR_GREATER +#if NET45_OR_GREATER || NETSTANDARD || NETCOREAPP /// This targets the MoveNext method of the async state machine, that actually contains the method's implementation Async #endif diff --git a/Harmony/Public/Harmony.cs b/Harmony/Public/Harmony.cs index 4d85b96b..4e7cea3c 100644 --- a/Harmony/Public/Harmony.cs +++ b/Harmony/Public/Harmony.cs @@ -47,7 +47,7 @@ public Harmony(string id) var location = assembly.Location; var environment = Environment.Version.ToString(); var platform = Environment.OSVersion.Platform.ToString(); -#if !NET50_OR_GREATER +#if !NET5_0_OR_GREATER if (string.IsNullOrEmpty(location)) location = new Uri(assembly.CodeBase).LocalPath; #endif FileLog.Log($"### Harmony id={id}, version={version}, location={location}, env/clr={environment}, platform={platform}"); @@ -56,7 +56,7 @@ public Harmony(string id) { var callingAssembly = callingMethod.DeclaringType.Assembly; location = callingAssembly.Location; -#if !NET50_OR_GREATER +#if !NET5_0_OR_GREATER if (string.IsNullOrEmpty(location)) location = new Uri(callingAssembly.CodeBase).LocalPath; #endif FileLog.Log($"### Started from {callingMethod.FullDescription()}, location {location}"); diff --git a/Harmony/Public/Patch.cs b/Harmony/Public/Patch.cs index 8cf6f3f4..243af9c6 100644 --- a/Harmony/Public/Patch.cs +++ b/Harmony/Public/Patch.cs @@ -5,7 +5,7 @@ using System.Reflection.Emit; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER using System.Text.Json; using System.Text.Json.Serialization; #endif @@ -16,7 +16,7 @@ namespace HarmonyLib /// internal static class PatchInfoSerialization { -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER internal static bool? useBinaryFormatter = null; internal static bool UseBinaryFormatter { @@ -68,14 +68,14 @@ public override Type BindToType(string assemblyName, string typeName) /// internal static byte[] Serialize(this PatchInfo patchInfo) { -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER if (UseBinaryFormatter) { #endif using var streamMemory = new MemoryStream(); binaryFormatter.Serialize(streamMemory, patchInfo); return streamMemory.GetBuffer(); -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER } else return JsonSerializer.SerializeToUtf8Bytes(patchInfo); @@ -88,13 +88,13 @@ internal static byte[] Serialize(this PatchInfo patchInfo) /// internal static PatchInfo Deserialize(byte[] bytes) { -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER if (UseBinaryFormatter) { #endif using var streamMemory = new MemoryStream(bytes); return (PatchInfo)binaryFormatter.Deserialize(streamMemory); -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER } else { @@ -130,35 +130,35 @@ public class PatchInfo { /// Prefixes as an array of /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonInclude] #endif public Patch[] prefixes = new Patch[0]; /// Postfixes as an array of /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonInclude] #endif public Patch[] postfixes = new Patch[0]; /// Transpilers as an array of /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonInclude] #endif public Patch[] transpilers = new Patch[0]; /// Finalizers as an array of /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonInclude] #endif public Patch[] finalizers = new Patch[0]; /// Returns if any of the patches wants debugging turned on /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonIgnore] #endif public bool Debugging => prefixes.Any(p => p.debug) || postfixes.Any(p => p.debug) || transpilers.Any(p => p.debug) || finalizers.Any(p => p.debug); @@ -306,7 +306,7 @@ private static Patch[] Remove(string owner, Patch[] current) /// A serializable patch /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonConverter(typeof(PatchJsonConverter))] #endif [Serializable] @@ -343,7 +343,7 @@ public class Patch : IComparable /// The method of the static patch method /// -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [JsonIgnore] #endif public MethodInfo PatchMethod diff --git a/Harmony/Public/PatchJsonConverter.cs b/Harmony/Public/PatchJsonConverter.cs index a783c5e4..98ba45d6 100644 --- a/Harmony/Public/PatchJsonConverter.cs +++ b/Harmony/Public/PatchJsonConverter.cs @@ -1,4 +1,4 @@ -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER using System; using System.Collections.Generic; using System.Text.Json; diff --git a/Harmony/Tools/AccessTools.cs b/Harmony/Tools/AccessTools.cs index af65d24a..2cae7459 100644 --- a/Harmony/Tools/AccessTools.cs +++ b/Harmony/Tools/AccessTools.cs @@ -10,7 +10,7 @@ using System.Runtime.Serialization; using System.Threading; -#if NET45_OR_GREATER +#if NET45_OR_GREATER || NETSTANDARD || NETCOREAPP using System.Runtime.CompilerServices; #endif @@ -600,7 +600,7 @@ public static MethodInfo EnumeratorMoveNext(MethodBase method) return Method(type, nameof(IEnumerator.MoveNext)); } -#if NET45_OR_GREATER +#if NET45_OR_GREATER || NETSTANDARD || NETCOREAPP /// Gets the method of an async method's state machine /// Async method that creates the state machine internally /// The internal method of the async state machine or null if no valid async method is detected diff --git a/Harmony/Tools/CodeMatch.cs b/Harmony/Tools/CodeMatch.cs index d856255d..2c7c58fd 100644 --- a/Harmony/Tools/CodeMatch.cs +++ b/Harmony/Tools/CodeMatch.cs @@ -13,7 +13,18 @@ public class CodeMatch : CodeInstruction public string name; /// The matched opcodes - public List opcodes = new(); + public HashSet opcodeSet = new(); + + // for backwards compatibility we keep + /// The matched opcodes + [Obsolete("Use opcodeSet instead")] +#pragma warning disable IDE1006 + public List opcodes + { + get => opcodeSet.ToList(); + set => opcodeSet = new HashSet(value); + } +#pragma warning restore IDE1006 /// The matched operands public List operands = new(); @@ -38,7 +49,7 @@ internal CodeMatch Set(object operand, string name) internal CodeMatch Set(OpCode opcode, object operand, string name) { this.opcode = opcode; - opcodes.Add(opcode); + _ = opcodeSet.Add(opcode); this.operand ??= operand; if (operand != null) operands.Add(operand); this.name ??= name; @@ -55,7 +66,7 @@ public CodeMatch(OpCode? opcode = null, object operand = null, string name = nul if (opcode is OpCode opcodeValue) { this.opcode = opcodeValue; - opcodes.Add(opcodeValue); + _ = opcodeSet.Add(opcodeValue); } if (operand != null) operands.Add(operand); @@ -63,17 +74,23 @@ public CodeMatch(OpCode? opcode = null, object operand = null, string name = nul this.name = name; } + /// Creates a code match + /// The opcodes + /// The optional operand + /// The optional name + /// + public static CodeMatch WithOpcodes(HashSet opcodes, object operand = null, string name = null) + { + return new CodeMatch(null, operand, name) { opcodeSet = opcodes }; + } + /// Creates a code match that calls a method /// The lambda expression using the method /// The optional name /// public CodeMatch(Expression expression, string name = null) { - opcodes.AddRange(new[] - { - OpCodes.Call, - OpCodes.Callvirt, - }); + opcodeSet.UnionWith(CodeInstructionExtensions.opcodesCalling); operand = SymbolExtensions.GetMethodInfo(expression); this.name = name; } @@ -84,11 +101,7 @@ public CodeMatch(Expression expression, string name = null) /// public CodeMatch(LambdaExpression expression, string name = null) { - opcodes.AddRange(new[] - { - OpCodes.Call, - OpCodes.Callvirt, - }); + opcodeSet.UnionWith(CodeInstructionExtensions.opcodesCalling); operand = SymbolExtensions.GetMethodInfo(expression); this.name = name; } @@ -115,7 +128,7 @@ internal bool Matches(List codes, CodeInstruction instruction) { if (predicate != null) return predicate(instruction); - if (opcodes.Count > 0 && opcodes.Contains(instruction.opcode) == false) return false; + if (opcodeSet.Count > 0 && opcodeSet.Contains(instruction.opcode) == false) return false; if (operands.Count > 0 && operands.Contains(instruction.operand) == false) return false; if (labels.Count > 0 && labels.Intersect(instruction.labels).Any() == false) return false; if (blocks.Count > 0 && blocks.Intersect(instruction.blocks).Any() == false) return false; @@ -141,30 +154,7 @@ internal bool Matches(List codes, CodeInstruction instruction) /// public static CodeMatch LoadsLocal(bool useAddress = false, string name = null) { - var match = new CodeMatch(null, null, name); - - if (useAddress) - { - match.opcodes.AddRange(new[] - { - OpCodes.Ldloca_S, - OpCodes.Ldloca - }); - } - else - { - match.opcodes.AddRange(new[] - { - OpCodes.Ldloc_0, - OpCodes.Ldloc_1, - OpCodes.Ldloc_2, - OpCodes.Ldloc_3, - OpCodes.Ldloc_S, - OpCodes.Ldloc - }); - } - - return match; + return WithOpcodes(useAddress ? CodeInstructionExtensions.opcodesLoadingLocalByAddress : CodeInstructionExtensions.opcodesLoadingLocalNormal, null, name); } /// Creates a code match for local stores @@ -172,19 +162,7 @@ public static CodeMatch LoadsLocal(bool useAddress = false, string name = null) /// public static CodeMatch StoresLocal(string name = null) { - var match = new CodeMatch(null, null, name); - - match.opcodes.AddRange(new[] - { - OpCodes.Stloc_0, - OpCodes.Stloc_1, - OpCodes.Stloc_2, - OpCodes.Stloc_3, - OpCodes.Stloc_S, - OpCodes.Stloc - }); - - return match; + return WithOpcodes(CodeInstructionExtensions.opcodesStoringLocal, null, name); } /// Creates a code match for argument loads @@ -193,30 +171,7 @@ public static CodeMatch StoresLocal(string name = null) /// public static CodeMatch LoadsArgument(bool useAddress = false, string name = null) { - var match = new CodeMatch(null, null, name); - - if (useAddress) - { - match.opcodes.AddRange(new[] - { - OpCodes.Ldarga_S, - OpCodes.Ldarga - }); - } - else - { - match.opcodes.AddRange(new[] - { - OpCodes.Ldarg_0, - OpCodes.Ldarg_1, - OpCodes.Ldarg_2, - OpCodes.Ldarg_3, - OpCodes.Ldarg_S, - OpCodes.Ldarg - }); - } - - return match; + return WithOpcodes(useAddress ? CodeInstructionExtensions.opcodesLoadingArgumentByAddress : CodeInstructionExtensions.opcodesLoadingArgumentNormal, null, name); } /// Creates a code match for argument stores @@ -224,15 +179,15 @@ public static CodeMatch LoadsArgument(bool useAddress = false, string name = nul /// public static CodeMatch StoresArgument(string name = null) { - var match = new CodeMatch(null, null, name); - - match.opcodes.AddRange(new[] - { - OpCodes.Starg_S, - OpCodes.Starg - }); + return WithOpcodes(CodeInstructionExtensions.opcodesStoringArgument, null, name); + } - return match; + /// Creates a code match for branching + /// An optional name + /// + public static CodeMatch Branches(string name = null) + { + return WithOpcodes(CodeInstructionExtensions.opcodesBranching, null, name); } /// Returns a string that represents the match @@ -243,8 +198,8 @@ public override string ToString() var result = "["; if (name != null) result += $"{name}: "; - if (opcodes.Count > 0) - result += $"opcodes={opcodes.Join()} "; + if (opcodeSet.Count > 0) + result += $"opcodes={opcodeSet.Join()} "; if (operands.Count > 0) result += $"operands={operands.Join()} "; if (labels.Count > 0) diff --git a/Harmony/Tools/Extensions.cs b/Harmony/Tools/Extensions.cs index e55b0e6e..885ac75d 100644 --- a/Harmony/Tools/Extensions.cs +++ b/Harmony/Tools/Extensions.cs @@ -165,29 +165,61 @@ public static string ToLiteral(this string input, string quoteChar = "\"") /// public static class CodeInstructionExtensions { - static readonly HashSet loadVarCodes = new() + internal static readonly HashSet opcodesCalling = new() + { + OpCodes.Call, + OpCodes.Callvirt + }; + + internal static readonly HashSet opcodesLoadingLocalByAddress = new() + { + OpCodes.Ldloca_S, + OpCodes.Ldloca + }; + + internal static readonly HashSet opcodesLoadingLocalNormal = new() { OpCodes.Ldloc_0, OpCodes.Ldloc_1, OpCodes.Ldloc_2, OpCodes.Ldloc_3, - OpCodes.Ldloc, - OpCodes.Ldloca, OpCodes.Ldloc_S, - OpCodes.Ldloca_S + OpCodes.Ldloc }; - static readonly HashSet storeVarCodes = new() + internal static readonly HashSet opcodesStoringLocal = new() { OpCodes.Stloc_0, OpCodes.Stloc_1, OpCodes.Stloc_2, OpCodes.Stloc_3, - OpCodes.Stloc, - OpCodes.Stloc_S + OpCodes.Stloc_S, + OpCodes.Stloc + }; + + internal static readonly HashSet opcodesLoadingArgumentByAddress = new() + { + OpCodes.Ldarga_S, + OpCodes.Ldarga + }; + + internal static readonly HashSet opcodesLoadingArgumentNormal = new() + { + OpCodes.Ldarg_0, + OpCodes.Ldarg_1, + OpCodes.Ldarg_2, + OpCodes.Ldarg_3, + OpCodes.Ldarg_S, + OpCodes.Ldarg + }; + + internal static readonly HashSet opcodesStoringArgument = new() + { + OpCodes.Starg_S, + OpCodes.Starg }; - static readonly HashSet branchCodes = new() + internal static readonly HashSet opcodesBranching = new() { OpCodes.Br_S, OpCodes.Brfalse_S, @@ -344,7 +376,9 @@ public static bool IsStarg(this CodeInstruction code, int? n = null) /// public static bool IsLdloc(this CodeInstruction code, LocalBuilder variable = null) { - if (loadVarCodes.Contains(code.opcode) is false) return false; + if (opcodesLoadingLocalNormal.Contains(code.opcode) is false) + if (opcodesLoadingLocalByAddress.Contains(code.opcode) is false) + return false; return variable is null || Equals(variable, code.operand); } @@ -355,7 +389,7 @@ public static bool IsLdloc(this CodeInstruction code, LocalBuilder variable = nu /// public static bool IsStloc(this CodeInstruction code, LocalBuilder variable = null) { - if (storeVarCodes.Contains(code.opcode) is false) return false; + if (opcodesStoringLocal.Contains(code.opcode) is false) return false; return variable is null || Equals(variable, code.operand); } @@ -366,7 +400,7 @@ public static bool IsStloc(this CodeInstruction code, LocalBuilder variable = nu /// public static bool Branches(this CodeInstruction code, out Label? label) { - if (branchCodes.Contains(code.opcode)) + if (opcodesBranching.Contains(code.opcode)) { label = (Label)code.operand; return true; @@ -613,6 +647,20 @@ public static CodeInstruction MoveBlocksFrom(this CodeInstruction code, CodeInst } } + /// Extensions for a sequence of + /// + public static class CodeInstructionsExtensions + { + /// Searches a list of by running a sequence of against it + /// The CodeInstructions (like a body of a method) to search in + /// An array of representing the sequence of codes you want to search for + /// + public static bool Matches(this IEnumerable instructions, CodeMatch[] matches) + { + return new CodeMatcher(instructions).MatchStartForward(matches).IsValid; + } + } + /// General extensions for collections /// public static class CollectionExtensions diff --git a/HarmonyTests/Extras/PatchSerialization.cs b/HarmonyTests/Extras/PatchSerialization.cs index b1c7ddca..010e9804 100644 --- a/HarmonyTests/Extras/PatchSerialization.cs +++ b/HarmonyTests/Extras/PatchSerialization.cs @@ -27,7 +27,7 @@ static string ExpectedJSON() return "{" + fixes + "}"; } -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER [Test] public void Serialize() { diff --git a/HarmonyTests/HarmonyTests.csproj b/HarmonyTests/HarmonyTests.csproj index bfb72e33..888e9f17 100644 --- a/HarmonyTests/HarmonyTests.csproj +++ b/HarmonyTests/HarmonyTests.csproj @@ -39,10 +39,6 @@ false - - $(DefineConstants);NET50_OR_GREATER - - true diff --git a/HarmonyTests/IL/TestMethodBodyReader.cs b/HarmonyTests/IL/TestMethodBodyReader.cs index 24ce8fc7..518734f7 100644 --- a/HarmonyTests/IL/TestMethodBodyReader.cs +++ b/HarmonyTests/IL/TestMethodBodyReader.cs @@ -61,7 +61,7 @@ public void Test_CanGetInstructionsWithNoILGenerator() var operandType = instrNoGen.opcode.OperandType; if ((operandType == OperandType.ShortInlineVar || operandType == OperandType.InlineVar) && instrNoGen.argument is not null) { -#if NETCOREAPP3_0 || NETCOREAPP3_1 || NET50_OR_GREATER +#if NETCOREAPP || NET5_0_OR_GREATER Assert.AreEqual("System.Reflection.RuntimeLocalVariableInfo", instrNoGen.argument.GetType().FullName, "w/o generator argument type @ {0} ({1})", i, instrNoGen); #else Assert.AreEqual("System.Reflection.LocalVariableInfo", instrNoGen.argument.GetType().FullName, "w/o generator argument type @ {0} ({1})", i, instrNoGen); diff --git a/HarmonyTests/Patching/Assets/PatchClasses.cs b/HarmonyTests/Patching/Assets/PatchClasses.cs index 48c572c2..c8518a13 100644 --- a/HarmonyTests/Patching/Assets/PatchClasses.cs +++ b/HarmonyTests/Patching/Assets/PatchClasses.cs @@ -577,14 +577,6 @@ public static class Class11Patch { public static bool prefixed = false; -#if NETCOREAPP2_0 - public static bool Prefix(ref string __result, int dummy) - { - __result = "patched"; - prefixed = true; - return false; - } -#else public static MethodInfo Prefix(MethodBase method) { return PatchTools.CreateMethod( @@ -612,7 +604,6 @@ public static MethodInfo Prefix(MethodBase method) } ); } -#endif } public class Class12 diff --git a/HarmonyTests/Tools/TestCodeMatcher.cs b/HarmonyTests/Tools/TestCodeMatcher.cs index 8dc274fb..ffa02229 100644 --- a/HarmonyTests/Tools/TestCodeMatcher.cs +++ b/HarmonyTests/Tools/TestCodeMatcher.cs @@ -2,6 +2,7 @@ using HarmonyTests.Tools.Assets; using NUnit.Framework; using NUnit.Framework.Internal; +using System.Collections.Generic; using System.Reflection.Emit; namespace HarmonyLibTests.Tools @@ -15,7 +16,7 @@ public void Test_CodeMatch() var method = SymbolExtensions.GetMethodInfo(() => CodeMatcherClass.Bar("")); var match = new CodeMatch(OpCodes.Call, method); Assert.AreEqual(match.opcode, OpCodes.Call); - Assert.AreEqual(match.opcodes, new[] { OpCodes.Call }); + Assert.AreEqual(match.opcodeSet, new HashSet() { OpCodes.Call }); Assert.AreEqual(match.operand, method); Assert.AreEqual(match.operands, new[] { method }); } @@ -26,7 +27,7 @@ public void Test_Code() var method = SymbolExtensions.GetMethodInfo(() => CodeMatcherClass.Bar("")); var code = Code.Call[method]; Assert.AreEqual(code.opcode, OpCodes.Call); - Assert.AreEqual(code.opcodes, new[] { OpCodes.Call }); + Assert.AreEqual(code.opcodeSet, new HashSet() { OpCodes.Call }); Assert.AreEqual(code.operand, method); Assert.AreEqual(code.operands, new[] { method }); } diff --git a/HarmonyTests/Traverse/TestTraverse_Types.cs b/HarmonyTests/Traverse/TestTraverse_Types.cs index af151de4..a07a4e77 100644 --- a/HarmonyTests/Traverse/TestTraverse_Types.cs +++ b/HarmonyTests/Traverse/TestTraverse_Types.cs @@ -55,7 +55,7 @@ public void Traverse_InnerInstance() Assert.AreEqual("somevalue", field2.GetValue()); } -#if !NET50_OR_GREATER // writing to static fields after init not allowed in NET5 +#if !NET5_0_OR_GREATER // writing to static fields after init not allowed in NET5 [Test] public void Traverse_InnerStatic() {