From 74a56a7b3b3bde30fbcb711eaef977ad69601e03 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 9 Feb 2017 14:02:43 -0500 Subject: further generalise CIL rewriters for reuse (#231) --- .../Framework/BaseMethodRewriter.cs | 89 ++++++++++++++++ .../Framework/RewriteHelper.cs | 41 ++++++++ .../Rewriters/BaseMethodRewriter.cs | 117 --------------------- .../Rewriters/SpriteBatchRewriter.cs | 3 +- .../StardewModdingAPI.AssemblyRewriters.csproj | 3 +- 5 files changed, 134 insertions(+), 119 deletions(-) create mode 100644 src/StardewModdingAPI.AssemblyRewriters/Framework/BaseMethodRewriter.cs create mode 100644 src/StardewModdingAPI.AssemblyRewriters/Framework/RewriteHelper.cs delete mode 100644 src/StardewModdingAPI.AssemblyRewriters/Rewriters/BaseMethodRewriter.cs (limited to 'src/StardewModdingAPI.AssemblyRewriters') diff --git a/src/StardewModdingAPI.AssemblyRewriters/Framework/BaseMethodRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Framework/BaseMethodRewriter.cs new file mode 100644 index 00000000..c9729ee8 --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/Framework/BaseMethodRewriter.cs @@ -0,0 +1,89 @@ +using System; +using System.Linq; +using System.Reflection; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace StardewModdingAPI.AssemblyRewriters.Framework +{ + /// Base class for a method rewriter. + public abstract class BaseMethodRewriter : IInstructionRewriter + { + /********* + ** Public methods + *********/ + /// Get whether a CIL instruction should be rewritten. + /// The IL instruction. + /// Whether the mod was compiled on a different platform. + public bool ShouldRewrite(Instruction instruction, bool platformChanged) + { + // ignore non-method-call instructions + if (instruction.OpCode != OpCodes.Call && instruction.OpCode != OpCodes.Callvirt) + return false; + + // check reference + MethodReference methodRef = (MethodReference)instruction.Operand; + return this.ShouldRewrite(methodRef, platformChanged); + } + + /// Rewrite a CIL instruction for compatibility. + /// The module being rewritten. + /// The CIL rewriter. + /// The instruction to rewrite. + /// Metadata for mapping assemblies to the current platform. + public void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap) + { + MethodReference methodRef = (MethodReference)instruction.Operand; + this.Rewrite(module, cil, instruction, methodRef, assemblyMap); + } + + + /********* + ** Protected methods + *********/ + /// Get whether a method reference should be rewritten. + /// The method reference. + /// Whether the mod was compiled on a different platform. + protected abstract bool ShouldRewrite(MethodReference methodRef, bool platformChanged); + + /// Rewrite a method for compatibility. + /// The module being rewritten. + /// The CIL rewriter. + /// The instruction which calls the method. + /// The method reference invoked by the . + /// Metadata for mapping assemblies to the current platform. + protected abstract void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, MethodReference methodRef, PlatformAssemblyMap assemblyMap); + + /// Get whether a method definition matches the signature expected by a method reference. + /// The method definition. + /// The method reference. + protected bool HasMatchingSignature(MethodInfo definition, MethodReference reference) + { + // same name + if (definition.Name != reference.Name) + return false; + + // same arguments + ParameterInfo[] definitionParameters = definition.GetParameters(); + ParameterDefinition[] referenceParameters = reference.Parameters.ToArray(); + if (referenceParameters.Length != definitionParameters.Length) + return false; + for (int i = 0; i < referenceParameters.Length; i++) + { + if (!RewriteHelper.IsMatchingType(definitionParameters[i].ParameterType, referenceParameters[i].ParameterType)) + return false; + } + return true; + } + + /// Get whether a type has a method whose signature matches the one expected by a method reference. + /// The type to check. + /// The method reference. + protected bool HasMatchingSignature(Type type, MethodReference reference) + { + return type + .GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public) + .Any(method => this.HasMatchingSignature(method, reference)); + } + } +} diff --git a/src/StardewModdingAPI.AssemblyRewriters/Framework/RewriteHelper.cs b/src/StardewModdingAPI.AssemblyRewriters/Framework/RewriteHelper.cs new file mode 100644 index 00000000..0307053f --- /dev/null +++ b/src/StardewModdingAPI.AssemblyRewriters/Framework/RewriteHelper.cs @@ -0,0 +1,41 @@ +using System; +using Mono.Cecil; + +namespace StardewModdingAPI.AssemblyRewriters.Framework +{ + /// Provides helper methods for field rewriters. + internal static class RewriteHelper + { + /********* + ** Public methods + *********/ + /// Get whether a type matches a type reference. + /// The defined type. + /// The type reference. + public static bool IsMatchingType(Type type, TypeReference reference) + { + // same namespace & name + if (type.Namespace != reference.Namespace || type.Name != reference.Name) + return false; + + // same generic parameters + if (type.IsGenericType) + { + if (!reference.IsGenericInstance) + return false; + + Type[] defGenerics = type.GetGenericArguments(); + TypeReference[] refGenerics = ((GenericInstanceType)reference).GenericArguments.ToArray(); + if (defGenerics.Length != refGenerics.Length) + return false; + for (int i = 0; i < defGenerics.Length; i++) + { + if (!RewriteHelper.IsMatchingType(defGenerics[i], refGenerics[i])) + return false; + } + } + + return true; + } + } +} diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/BaseMethodRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/BaseMethodRewriter.cs deleted file mode 100644 index e44acaf9..00000000 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/BaseMethodRewriter.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace StardewModdingAPI.AssemblyRewriters.Rewriters -{ - /// Base class for a method rewriter. - public abstract class BaseMethodRewriter : IInstructionRewriter - { - /********* - ** Public methods - *********/ - /// Get whether a CIL instruction should be rewritten. - /// The IL instruction. - /// Whether the mod was compiled on a different platform. - public bool ShouldRewrite(Instruction instruction, bool platformChanged) - { - // ignore non-method-call instructions - if (instruction.OpCode != OpCodes.Call && instruction.OpCode != OpCodes.Callvirt) - return false; - - // check reference - MethodReference methodRef = (MethodReference)instruction.Operand; - return this.ShouldRewrite(methodRef, platformChanged); - } - - /// Rewrite a CIL instruction for compatibility. - /// The module being rewritten. - /// The CIL rewriter. - /// The instruction to rewrite. - /// Metadata for mapping assemblies to the current platform. - public void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, PlatformAssemblyMap assemblyMap) - { - MethodReference methodRef = (MethodReference)instruction.Operand; - this.Rewrite(module, cil, instruction, methodRef, assemblyMap); - } - - /********* - ** Protected methods - *********/ - /// Get whether the given method reference can be rewritten. - /// The method reference. - /// Whether the mod was compiled on a different platform. - protected abstract bool ShouldRewrite(MethodReference methodRef, bool platformChanged); - - /// Rewrite a method for compatibility. - /// The module being rewritten. - /// The CIL rewriter. - /// The instruction which calls the method. - /// The method reference invoked by the . - /// Metadata for mapping assemblies to the current platform. - protected abstract void Rewrite(ModuleDefinition module, ILProcessor cil, Instruction instruction, MethodReference methodRef, PlatformAssemblyMap assemblyMap); - - /// Get whether a method definition matches the signature expected by a method reference. - /// The method definition. - /// The method reference. - protected bool HasMatchingSignature(MethodInfo definition, MethodReference reference) - { - // same name - if (definition.Name != reference.Name) - return false; - - // same arguments - ParameterInfo[] definitionParameters = definition.GetParameters(); - ParameterDefinition[] referenceParameters = reference.Parameters.ToArray(); - if (referenceParameters.Length != definitionParameters.Length) - return false; - for (int i = 0; i < referenceParameters.Length; i++) - { - if (!this.IsMatchingType(definitionParameters[i].ParameterType, referenceParameters[i].ParameterType)) - return false; - } - return true; - } - - /// Get whether a type has a method whose signature matches the one expected by a method reference. - /// The type to check. - /// The method reference. - protected bool HasMatchingSignature(Type type, MethodReference reference) - { - return type - .GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public) - .Any(method => this.HasMatchingSignature(method, reference)); - } - - /// Get whether a type matches a type reference. - /// The defined type. - /// The type reference. - private bool IsMatchingType(Type type, TypeReference reference) - { - // same namespace & name - if (type.Namespace != reference.Namespace || type.Name != reference.Name) - return false; - - // same generic parameters - if (type.IsGenericType) - { - if (!reference.IsGenericInstance) - return false; - - Type[] defGenerics = type.GetGenericArguments(); - TypeReference[] refGenerics = ((GenericInstanceType)reference).GenericArguments.ToArray(); - if (defGenerics.Length != refGenerics.Length) - return false; - for (int i = 0; i < defGenerics.Length; i++) - { - if (!this.IsMatchingType(defGenerics[i], refGenerics[i])) - return false; - } - } - - return true; - } - } -} \ No newline at end of file diff --git a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/SpriteBatchRewriter.cs b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/SpriteBatchRewriter.cs index f64bf768..819578e0 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/Rewriters/SpriteBatchRewriter.cs +++ b/src/StardewModdingAPI.AssemblyRewriters/Rewriters/SpriteBatchRewriter.cs @@ -3,6 +3,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Mono.Cecil; using Mono.Cecil.Cil; +using StardewModdingAPI.AssemblyRewriters.Framework; namespace StardewModdingAPI.AssemblyRewriters.Rewriters { @@ -13,7 +14,7 @@ namespace StardewModdingAPI.AssemblyRewriters.Rewriters /********* ** Protected methods *********/ - /// Get whether the given method reference can be rewritten. + /// Get whether a method reference should be rewritten. /// The method reference. /// Whether the mod was compiled on a different platform. protected override bool ShouldRewrite(MethodReference methodRef, bool platformChanged) diff --git a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj index 01ca1d66..0b549a86 100644 --- a/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj +++ b/src/StardewModdingAPI.AssemblyRewriters/StardewModdingAPI.AssemblyRewriters.csproj @@ -74,7 +74,8 @@ - + + -- cgit