summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs255
1 files changed, 24 insertions, 231 deletions
diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs
index 93003a64..7a339266 100644
--- a/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs
+++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/AssemblyTypeRewriter.cs
@@ -2,8 +2,6 @@
using System.Linq;
using System.Reflection;
using Mono.Cecil;
-using Mono.Cecil.Cil;
-using CallSite = Mono.Cecil.CallSite;
namespace StardewModdingAPI.Framework.AssemblyRewriting
{
@@ -25,9 +23,6 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
/// <summary>An assembly => reference cache.</summary>
private readonly IDictionary<Assembly, AssemblyNameReference> AssemblyNameReferences;
- /// <summary>An assembly => module cache.</summary>
- private readonly IDictionary<Assembly, ModuleDefinition> AssemblyModules;
-
/*********
** Public methods
@@ -43,20 +38,22 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
// cache assembly metadata
this.AssemblyNameReferences = targetAssemblies.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName));
- this.AssemblyModules = targetAssemblies.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName)); // technically an assembly can contain multiple modules, but none of the build tools (including MSBuild itself) support it
// collect type => assembly lookup
this.TypeAssemblies = new Dictionary<string, Assembly>();
foreach (Assembly assembly in targetAssemblies)
{
- ModuleDefinition module = this.AssemblyModules[assembly];
- foreach (TypeDefinition type in module.GetTypes())
+ foreach (Module assemblyModule in assembly.Modules)
{
- if (!type.IsPublic)
- continue; // no need to rewrite
- if (type.Namespace.Contains("<"))
- continue; // ignore C++ stuff
- this.TypeAssemblies[type.FullName] = assembly;
+ ModuleDefinition module = ModuleDefinition.ReadModule(assemblyModule.FullyQualifiedName);
+ foreach (TypeDefinition type in module.GetTypes())
+ {
+ if (!type.IsPublic)
+ continue; // no need to rewrite
+ if (type.Namespace.Contains("<"))
+ continue; // ignore assembly metadata
+ this.TypeAssemblies[type.FullName] = assembly;
+ }
}
}
}
@@ -67,36 +64,25 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
{
foreach (ModuleDefinition module in assembly.Modules)
{
- // rewrite assembly references
- bool shouldRewriteTypes = false;
+ // remove old assembly references
for (int i = 0; i < module.AssemblyReferences.Count; i++)
{
bool shouldRemove = this.RemoveAssemblyNames.Any(name => module.AssemblyReferences[i].Name == name) || this.TargetAssemblies.Any(a => module.AssemblyReferences[i].Name == a.GetName().Name);
if (shouldRemove)
{
- shouldRewriteTypes = true;
module.AssemblyReferences.RemoveAt(i);
i--;
}
}
+
+ // add target assembly references
foreach (AssemblyNameReference target in this.AssemblyNameReferences.Values)
- {
module.AssemblyReferences.Add(target);
- shouldRewriteTypes = true;
- }
-
- // rewrite references
- if (shouldRewriteTypes)
- {
- // rewrite types
- foreach (TypeDefinition type in module.GetTypes())
- this.RewriteReferences(type, module);
- // rewrite type references
- TypeReference[] refs = (TypeReference[])module.GetTypeReferences();
- for (int i = 0; i < refs.Length; ++i)
- refs[i] = this.GetTypeReference(refs[i], module);
- }
+ // rewrite type scopes to use target assemblies
+ TypeReference[] refs = (TypeReference[])module.GetTypeReferences();
+ foreach (TypeReference type in refs)
+ this.ChangeTypeScope(type);
}
}
@@ -104,215 +90,22 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting
/*********
** Private methods
*********/
- /// <summary>Rewrite the references for a code object.</summary>
- /// <param name="type">The type to rewrite.</param>
- /// <param name="module">The module being rewritten.</param>
- private void RewriteReferences(TypeDefinition type, ModuleDefinition module)
- {
- // rewrite base type
- type.BaseType = this.GetTypeReference(type.BaseType, module);
-
- // rewrite interfaces
- for (int i = 0; i < type.Interfaces.Count; i++)
- type.Interfaces[i] = this.GetTypeReference(type.Interfaces[i], module);
-
- // rewrite events
- foreach (EventDefinition @event in type.Events)
- {
- this.RewriteReferences(@event.AddMethod, module);
- this.RewriteReferences(@event.RemoveMethod, module);
- this.RewriteReferences(@event.InvokeMethod, module);
- }
-
- // rewrite properties
- foreach (PropertyDefinition property in type.Properties)
- {
- this.RewriteReferences(property.GetMethod, module);
- this.RewriteReferences(property.SetMethod, module);
- }
-
- // rewrite methods
- foreach (MethodDefinition method in type.Methods)
- this.RewriteReferences(method, module);
-
- // rewrite fields
- foreach (FieldDefinition field in type.Fields)
- this.RewriteReferences(field, module);
-
- // rewrite nested types
- foreach (TypeDefinition nestedType in type.NestedTypes)
- this.RewriteReferences(nestedType, module);
-
- // rewrite generic parameters
- foreach (GenericParameter parameter in type.GenericParameters)
- this.RewriteReferences(parameter, module);
-
- module.Import(type);
- }
-
- /// <summary>Rewrite the references for a code object.</summary>
- /// <param name="method">The method to rewrite.</param>
- /// <param name="module">The module being rewritten.</param>
- private void RewriteReferences(MethodReference method, ModuleDefinition module)
- {
- // parameter types
- if (method.HasParameters)
- {
- foreach (ParameterDefinition parameter in method.Parameters)
- parameter.ParameterType = this.GetTypeReference(parameter.ParameterType, module);
- }
-
- // return type
- method.MethodReturnType.ReturnType = this.GetTypeReference(method.MethodReturnType.ReturnType, module);
-
- module.Import(method);
- }
-
- /// <summary>Rewrite the references for a code object.</summary>
- /// <param name="method">The method to rewrite.</param>
- /// <param name="module">The module being rewritten.</param>
- private void RewriteReferences(MethodDefinition method, ModuleDefinition module)
- {
- if (method == null)
- return;
-
- this.RewriteReferences((MethodReference)method, module);
-
- // overrides
- foreach (MethodReference @override in method.Overrides)
- this.RewriteReferences(@override, module);
-
- // body
- if (method.HasBody)
- {
- // this
- if (method.Body.ThisParameter != null)
- method.Body.ThisParameter.ParameterType = this.GetTypeReference(method.Body.ThisParameter.ParameterType, module);
-
- // variables
- if (method.Body.HasVariables)
- {
- foreach (VariableDefinition variable in method.Body.Variables)
- variable.VariableType = this.GetTypeReference(variable.VariableType, module);
- }
-
- // instructions
- foreach (Instruction instruction in method.Body.Instructions)
- {
- object operand = instruction.Operand;
-
- // type
- {
- TypeReference type = operand as TypeReference;
- if (type != null)
- {
- instruction.Operand = this.GetTypeReference(type, module);
- continue;
- }
- }
-
- // method
- {
- MethodReference methodRef = operand as MethodReference;
- if (methodRef != null)
- {
- this.RewriteReferences(methodRef, module);
- continue;
- }
- }
-
- // field
- {
- FieldReference field = operand as FieldReference;
- if (field != null)
- {
- this.RewriteReferences(field, module);
- continue;
- }
- }
-
- // variable
- {
- VariableDefinition variable = operand as VariableDefinition;
- if (variable != null)
- {
- variable.VariableType = this.GetTypeReference(variable.VariableType, module);
- continue;
- }
- }
-
- // parameter
- {
- ParameterDefinition parameter = operand as ParameterDefinition;
- if (parameter != null)
- {
- parameter.ParameterType = this.GetTypeReference(parameter.ParameterType, module);
- continue;
- }
- }
-
- // call site
- {
- CallSite call = operand as CallSite;
- if (call != null)
- {
- foreach (ParameterDefinition parameter in call.Parameters)
- parameter.ParameterType = this.GetTypeReference(parameter.ParameterType, module);
- call.ReturnType = this.GetTypeReference(call.ReturnType, module);
- }
- }
- }
- }
-
- module.Import(method);
- }
-
- /// <summary>Rewrite the references for a code object.</summary>
- /// <param name="parameter">The generic parameter to rewrite.</param>
- /// <param name="module">The module being rewritten.</param>
- private void RewriteReferences(GenericParameter parameter, ModuleDefinition module)
- {
- // constraints
- for (int i = 0; i < parameter.Constraints.Count; i++)
- parameter.Constraints[i] = this.GetTypeReference(parameter.Constraints[i], module);
-
- // generic parameters
- foreach (GenericParameter genericParam in parameter.GenericParameters)
- this.RewriteReferences(genericParam, module);
- }
-
- /// <summary>Rewrite the references for a code object.</summary>
- /// <param name="field">The field to rewrite.</param>
- /// <param name="module">The module being rewritten.</param>
- private void RewriteReferences(FieldReference field, ModuleDefinition module)
- {
- field.DeclaringType = this.GetTypeReference(field.DeclaringType, module);
- field.FieldType = this.GetTypeReference(field.FieldType, module);
- module.Import(field);
- }
-
/// <summary>Get the correct reference to use for compatibility with the current platform.</summary>
/// <param name="type">The type reference to rewrite.</param>
- /// <param name="module">The module being rewritten.</param>
- private TypeReference GetTypeReference(TypeReference type, ModuleDefinition module)
+ private void ChangeTypeScope(TypeReference type)
{
// check skip conditions
- if (type == null)
- return null;
- if (type.FullName.StartsWith("System."))
- return type;
+ if (type == null || type.FullName.StartsWith("System."))
+ return;
// get assembly
Assembly assembly;
if (!this.TypeAssemblies.TryGetValue(type.FullName, out assembly))
- return type;
-
- // replace type
- AssemblyNameReference newAssembly = this.AssemblyNameReferences[assembly];
- ModuleDefinition newModule = this.AssemblyModules[assembly];
- type = new TypeReference(type.Namespace, type.Name, newModule, newAssembly);
+ return;
- return module.Import(type);
+ // replace scope
+ AssemblyNameReference assemblyRef = this.AssemblyNameReferences[assembly];
+ type.Scope = assemblyRef;
}
}
}