summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-08-24 20:11:56 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-08-24 20:11:56 -0400
commit94b8262692d2452e77d57fa22046dded231cdb0a (patch)
tree7a65c992db59db0c0797799195ff1509c366ac20 /src/SMAPI
parent046deb2d56b6d4665280cc5478d9e683ec1d777d (diff)
downloadSMAPI-94b8262692d2452e77d57fa22046dded231cdb0a.tar.gz
SMAPI-94b8262692d2452e77d57fa22046dded231cdb0a.tar.bz2
SMAPI-94b8262692d2452e77d57fa22046dded231cdb0a.zip
add heuristic field-to-property rewriter
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs63
-rw-r--r--src/SMAPI/Metadata/InstructionMetadata.cs3
3 files changed, 40 insertions, 28 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
index fde37d68..611b2cf2 100644
--- a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
+++ b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs
@@ -50,7 +50,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
** Protected methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="defaultPhrase">A brief noun phrase indicating what the handler matches.</param>
+ /// <param name="defaultPhrase">A brief noun phrase indicating what the handler matches, used if <see cref="Phrases"/> is empty.</param>
protected BaseInstructionHandler(string defaultPhrase)
{
this.DefaultPhrase = defaultPhrase;
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs
index c3b5854e..514691cf 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs
@@ -1,47 +1,33 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
namespace StardewModdingAPI.Framework.ModLoading.Rewriters
{
- /// <summary>Rewrites field references into property references.</summary>
+ /// <summary>Rewrites references to fields which no longer exist, but which have an equivalent property with the exact same name.</summary>
internal class FieldToPropertyRewriter : BaseInstructionHandler
{
/*********
** Fields
*********/
- /// <summary>The type containing the field to which references should be rewritten.</summary>
- private readonly Type Type;
-
- /// <summary>The field name to which references should be rewritten.</summary>
- private readonly string FromFieldName;
-
- /// <summary>The new property name.</summary>
- private readonly string ToPropertyName;
+ /// <summary>The assembly names to which to rewrite broken references.</summary>
+ private readonly HashSet<string> RewriteReferencesToAssemblies;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="type">The type whose field to which references should be rewritten.</param>
- /// <param name="fieldName">The field name to rewrite.</param>
- /// <param name="propertyName">The property name (if different).</param>
- public FieldToPropertyRewriter(Type type, string fieldName, string propertyName)
- : base(defaultPhrase: $"{type.FullName}.{fieldName} field")
+ /// <param name="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param>
+ public FieldToPropertyRewriter(string[] rewriteReferencesToAssemblies)
+ : base(defaultPhrase: "field changed to property") // ignored since we specify phrases
{
- this.Type = type;
- this.FromFieldName = fieldName;
- this.ToPropertyName = propertyName;
+ this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies);
}
- /// <summary>Construct an instance.</summary>
- /// <param name="type">The type whose field to which references should be rewritten.</param>
- /// <param name="fieldName">The field name to rewrite.</param>
- public FieldToPropertyRewriter(Type type, string fieldName)
- : this(type, fieldName, fieldName) { }
-
/// <summary>Rewrite a CIL instruction reference if needed.</summary>
/// <param name="module">The assembly module containing the instruction.</param>
/// <param name="cil">The CIL processor.</param>
@@ -52,14 +38,37 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
{
// get field ref
FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
- if (!RewriteHelper.IsFieldReferenceTo(fieldRef, this.Type.FullName, this.FromFieldName))
+ if (fieldRef == null || !this.ShouldValidate(fieldRef.DeclaringType))
+ return false;
+
+ // skip if not broken
+ if (fieldRef.Resolve() != null)
+ return false;
+
+ // get equivalent property
+ PropertyDefinition property = fieldRef.DeclaringType.Resolve().Properties.FirstOrDefault(p => p.Name == fieldRef.Name);
+ MethodDefinition method = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld
+ ? property?.GetMethod
+ : property?.SetMethod;
+ if (method == null)
return false;
- // replace with property
- string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get" : "set";
- MethodReference propertyRef = module.ImportReference(this.Type.GetMethod($"{methodPrefix}_{this.ToPropertyName}"));
+ // rewrite field to property
+ MethodReference propertyRef = module.ImportReference(method);
replaceWith(cil.Create(OpCodes.Call, propertyRef));
+ this.Phrases.Add($"{fieldRef.DeclaringType.Name}.{fieldRef.Name} (field => property)");
return this.MarkRewritten();
}
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Whether references to the given type should be validated.</summary>
+ /// <param name="type">The type reference.</param>
+ private bool ShouldValidate(TypeReference type)
+ {
+ return type != null && this.RewriteReferencesToAssemblies.Contains(type.Scope.Name);
+ }
}
}
diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs
index 79d7a7a8..fca809f8 100644
--- a/src/SMAPI/Metadata/InstructionMetadata.cs
+++ b/src/SMAPI/Metadata/InstructionMetadata.cs
@@ -31,6 +31,9 @@ namespace StardewModdingAPI.Metadata
/****
** rewrite CIL to fix incompatible code
****/
+ // generic rewrites
+ yield return new FieldToPropertyRewriter(this.ValidateReferencesToAssemblies);
+
// rewrite for crossplatform compatibility
if (platformChanged)
yield return new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchFacade));