summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModLoading/Rewriters
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-09-07 13:06:27 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-09-07 13:06:27 -0400
commit5e43bdbf5cd6dbab36c25287c85d42ccfeea2c83 (patch)
tree0a42305174eb84561a584549cd685c5e95670f36 /src/SMAPI/Framework/ModLoading/Rewriters
parent8da88b8fe5b41739c5cd0df3280b9770fc7f10a4 (diff)
parentf9fac11028354f15d786d5b854608edb10716f79 (diff)
downloadSMAPI-5e43bdbf5cd6dbab36c25287c85d42ccfeea2c83.tar.gz
SMAPI-5e43bdbf5cd6dbab36c25287c85d42ccfeea2c83.tar.bz2
SMAPI-5e43bdbf5cd6dbab36c25287c85d42ccfeea2c83.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI/Framework/ModLoading/Rewriters')
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs35
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs65
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs13
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs106
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs109
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs9
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/StaticFieldToConstantRewriter.cs74
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs6
8 files changed, 240 insertions, 177 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs
index 8043b13a..0b679e9d 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs
@@ -26,26 +26,31 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="type">The type whose field to rewrite.</param>
+ /// <param name="fromType">The type whose field to rewrite.</param>
/// <param name="fromFieldName">The field name to rewrite.</param>
+ /// <param name="toType">The new type which will have the field.</param>
/// <param name="toFieldName">The new field name to reference.</param>
- public FieldReplaceRewriter(Type type, string fromFieldName, string toFieldName)
- : base(defaultPhrase: $"{type.FullName}.{fromFieldName} field")
+ public FieldReplaceRewriter(Type fromType, string fromFieldName, Type toType, string toFieldName)
+ : base(defaultPhrase: $"{fromType.FullName}.{fromFieldName} field")
{
- this.Type = type;
+ this.Type = fromType;
this.FromFieldName = fromFieldName;
- this.ToField = type.GetField(toFieldName);
+ this.ToField = toType.GetField(toFieldName);
if (this.ToField == null)
- throw new InvalidOperationException($"The {type.FullName} class doesn't have a {toFieldName} field.");
+ throw new InvalidOperationException($"The {toType.FullName} class doesn't have a {toFieldName} field.");
}
- /// <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>
- /// <param name="instruction">The CIL instruction to handle.</param>
- /// <param name="replaceWith">Replaces the CIL instruction with a new one.</param>
- /// <returns>Returns whether the instruction was changed.</returns>
- public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action<Instruction> replaceWith)
+ /// <summary>Construct an instance.</summary>
+ /// <param name="type">The type whose field to rewrite.</param>
+ /// <param name="fromFieldName">The field name to rewrite.</param>
+ /// <param name="toFieldName">The new field name to reference.</param>
+ public FieldReplaceRewriter(Type type, string fromFieldName, string toFieldName)
+ : this(type, fromFieldName, type, toFieldName)
+ {
+ }
+
+ /// <inheritdoc />
+ public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// get field reference
FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
@@ -53,8 +58,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return false;
// replace with new field
- FieldReference newRef = module.ImportReference(this.ToField);
- replaceWith(cil.Create(instruction.OpCode, newRef));
+ instruction.Operand = module.ImportReference(this.ToField);
+
return this.MarkRewritten();
}
}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs
deleted file mode 100644
index c3b5854e..00000000
--- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System;
-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>
- 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;
-
-
- /*********
- ** 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")
- {
- this.Type = type;
- this.FromFieldName = fieldName;
- this.ToPropertyName = propertyName;
- }
-
- /// <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>
- /// <param name="instruction">The CIL instruction to handle.</param>
- /// <param name="replaceWith">Replaces the CIL instruction with a new one.</param>
- /// <returns>Returns whether the instruction was changed.</returns>
- public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action<Instruction> replaceWith)
- {
- // get field ref
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
- if (!RewriteHelper.IsFieldReferenceTo(fieldRef, this.Type.FullName, this.FromFieldName))
- 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}"));
- replaceWith(cil.Create(OpCodes.Call, propertyRef));
- return this.MarkRewritten();
- }
- }
-}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
index b30d686e..4b3675bc 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
@@ -25,11 +25,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
public Harmony1AssemblyRewriter()
: base(defaultPhrase: "Harmony 1.x") { }
- /// <summary>Rewrite a type reference if needed.</summary>
- /// <param name="module">The assembly module containing the instruction.</param>
- /// <param name="type">The type definition to handle.</param>
- /// <param name="replaceWith">Replaces the type reference with a new one.</param>
- /// <returns>Returns whether the type was changed.</returns>
+ /// <inheritdoc />
public override bool Handle(ModuleDefinition module, TypeReference type, Action<TypeReference> replaceWith)
{
// rewrite Harmony 1.x type to Harmony 2.0 type
@@ -45,12 +41,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
return false;
}
- /// <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>
- /// <param name="instruction">The CIL instruction to handle.</param>
- /// <param name="replaceWith">Replaces the CIL instruction with a new one.</param>
- /// <returns>Returns whether the instruction was changed.</returns>
+ /// <inheritdoc />
public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action<Instruction> replaceWith)
{
// rewrite Harmony 1.x methods to Harmony 2.0
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
new file mode 100644
index 00000000..ca04205c
--- /dev/null
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs
@@ -0,0 +1,106 @@
+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>Automatically fix references to fields that have been replaced by a property or const field.</summary>
+ internal class HeuristicFieldRewriter : BaseInstructionHandler
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <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="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param>
+ public HeuristicFieldRewriter(string[] rewriteReferencesToAssemblies)
+ : base(defaultPhrase: "field changed to property") // ignored since we specify phrases
+ {
+ this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies);
+ }
+
+ /// <inheritdoc />
+ public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
+ {
+ // get field ref
+ FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
+ if (fieldRef == null || !this.ShouldValidate(fieldRef.DeclaringType))
+ return false;
+
+ // skip if not broken
+ FieldDefinition fieldDefinition = fieldRef.Resolve();
+ if (fieldDefinition != null && !fieldDefinition.HasConstant)
+ return false;
+
+ // rewrite if possible
+ TypeDefinition declaringType = fieldRef.DeclaringType.Resolve();
+ bool isRead = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld;
+ return
+ this.TryRewriteToProperty(module, instruction, fieldRef, declaringType, isRead)
+ || this.TryRewriteToConstField(instruction, fieldDefinition);
+ }
+
+
+ /*********
+ ** 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);
+ }
+
+ /// <summary>Try rewriting the field into a matching property.</summary>
+ /// <param name="module">The assembly module containing the instruction.</param>
+ /// <param name="instruction">The CIL instruction to rewrite.</param>
+ /// <param name="fieldRef">The field reference.</param>
+ /// <param name="declaringType">The type on which the field was defined.</param>
+ /// <param name="isRead">Whether the field is being read; else it's being written to.</param>
+ private bool TryRewriteToProperty(ModuleDefinition module, Instruction instruction, FieldReference fieldRef, TypeDefinition declaringType, bool isRead)
+ {
+ // get equivalent property
+ PropertyDefinition property = declaringType.Properties.FirstOrDefault(p => p.Name == fieldRef.Name);
+ MethodDefinition method = isRead ? property?.GetMethod : property?.SetMethod;
+ if (method == null)
+ return false;
+
+ // rewrite field to property
+ instruction.OpCode = OpCodes.Call;
+ instruction.Operand = module.ImportReference(method);
+
+ this.Phrases.Add($"{fieldRef.DeclaringType.Name}.{fieldRef.Name} (field => property)");
+ return this.MarkRewritten();
+ }
+
+ /// <summary>Try rewriting the field into a matching const field.</summary>
+ /// <param name="instruction">The CIL instruction to rewrite.</param>
+ /// <param name="field">The field definition.</param>
+ private bool TryRewriteToConstField(Instruction instruction, FieldDefinition field)
+ {
+ // must have been a static field read, and the new field must be const
+ if (instruction.OpCode != OpCodes.Ldsfld || field?.HasConstant != true)
+ return false;
+
+ // get opcode for value type
+ Instruction loadInstruction = RewriteHelper.GetLoadValueInstruction(field.Constant);
+ if (loadInstruction == null)
+ return false;
+
+ // rewrite to constant
+ instruction.OpCode = loadInstruction.OpCode;
+ instruction.Operand = loadInstruction.Operand;
+
+ this.Phrases.Add($"{field.DeclaringType.Name}.{field.Name} (field => const)");
+ return this.MarkRewritten();
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
new file mode 100644
index 00000000..e133b6fa
--- /dev/null
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs
@@ -0,0 +1,109 @@
+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>Automatically fix references to methods that had extra optional parameters added.</summary>
+ internal class HeuristicMethodRewriter : BaseInstructionHandler
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <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="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param>
+ public HeuristicMethodRewriter(string[] rewriteReferencesToAssemblies)
+ : base(defaultPhrase: "methods with missing parameters") // ignored since we specify phrases
+ {
+ this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies);
+ }
+
+ /// <inheritdoc />
+ public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
+ {
+ // get method ref
+ MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
+ if (methodRef == null || !this.ShouldValidate(methodRef.DeclaringType))
+ return false;
+
+ // skip if not broken
+ if (methodRef.Resolve() != null)
+ return false;
+
+ // get type
+ var type = methodRef.DeclaringType.Resolve();
+ if (type == null)
+ return false;
+
+ // get method definition
+ MethodDefinition method = null;
+ foreach (var match in type.Methods.Where(p => p.Name == methodRef.Name))
+ {
+ // reference matches initial parameters of definition
+ if (methodRef.Parameters.Count >= match.Parameters.Count || !this.InitialParametersMatch(methodRef, match))
+ continue;
+
+ // all remaining parameters in definition are optional
+ if (!match.Parameters.Skip(methodRef.Parameters.Count).All(p => p.IsOptional))
+ continue;
+
+ method = match;
+ break;
+ }
+ if (method == null)
+ return false;
+
+ // get instructions to inject parameter values
+ var loadInstructions = method.Parameters.Skip(methodRef.Parameters.Count)
+ .Select(p => RewriteHelper.GetLoadValueInstruction(p.Constant))
+ .ToArray();
+ if (loadInstructions.Any(p => p == null))
+ return false; // SMAPI needs to load the value onto the stack before the method call, but the optional parameter type wasn't recognized
+
+ // rewrite method reference
+ foreach (Instruction loadInstruction in loadInstructions)
+ cil.InsertBefore(instruction, loadInstruction);
+ instruction.Operand = module.ImportReference(method);
+
+ this.Phrases.Add($"{methodRef.DeclaringType.Name}.{methodRef.Name} (added missing optional parameters)");
+ 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);
+ }
+
+ /// <summary>Get whether every parameter in the method reference matches the exact order and type of the parameters in the method definition. This ignores extra parameters in the definition.</summary>
+ /// <param name="methodRef">The method reference whose parameters to check.</param>
+ /// <param name="method">The method definition whose parameters to check against.</param>
+ private bool InitialParametersMatch(MethodReference methodRef, MethodDefinition method)
+ {
+ if (methodRef.Parameters.Count > method.Parameters.Count)
+ return false;
+
+ for (int i = 0; i < methodRef.Parameters.Count; i++)
+ {
+ if (!RewriteHelper.IsSameType(methodRef.Parameters[i].ParameterType, method.Parameters[i].ParameterType))
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
index b8e53f40..9933e2ca 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs
@@ -40,13 +40,8 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
public MethodParentRewriter(Type fromType, Type toType, string nounPhrase = null)
: this(fromType.FullName, toType, nounPhrase) { }
- /// <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>
- /// <param name="instruction">The CIL instruction to handle.</param>
- /// <param name="replaceWith">Replaces the CIL instruction with a new one.</param>
- /// <returns>Returns whether the instruction was changed.</returns>
- public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action<Instruction> replaceWith)
+ /// <inheritdoc />
+ public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
// get method ref
MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/StaticFieldToConstantRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/StaticFieldToConstantRewriter.cs
deleted file mode 100644
index 6ef18b26..00000000
--- a/src/SMAPI/Framework/ModLoading/Rewriters/StaticFieldToConstantRewriter.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-using StardewModdingAPI.Framework.ModLoading.Framework;
-
-namespace StardewModdingAPI.Framework.ModLoading.Rewriters
-{
- /// <summary>Rewrites static field references into constant values.</summary>
- /// <typeparam name="TValue">The constant value type.</typeparam>
- internal class StaticFieldToConstantRewriter<TValue> : 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 constant value to replace with.</summary>
- private readonly TValue Value;
-
-
- /*********
- ** 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="value">The constant value to replace with.</param>
- public StaticFieldToConstantRewriter(Type type, string fieldName, TValue value)
- : base(defaultPhrase: $"{type.FullName}.{fieldName} field")
- {
- this.Type = type;
- this.FromFieldName = fieldName;
- this.Value = value;
- }
-
- /// <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>
- /// <param name="instruction">The CIL instruction to handle.</param>
- /// <param name="replaceWith">Replaces the CIL instruction with a new one.</param>
- /// <returns>Returns whether the instruction was changed.</returns>
- public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action<Instruction> replaceWith)
- {
- // get field reference
- FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
- if (!RewriteHelper.IsFieldReferenceTo(fieldRef, this.Type.FullName, this.FromFieldName))
- return false;
-
- // rewrite to constant
- replaceWith(this.CreateConstantInstruction(cil, this.Value));
- return this.MarkRewritten();
- }
-
-
- /*********
- ** Private methods
- *********/
- /// <summary>Create a CIL constant value instruction.</summary>
- /// <param name="cil">The CIL processor.</param>
- /// <param name="value">The constant value to set.</param>
- private Instruction CreateConstantInstruction(ILProcessor cil, object value)
- {
- if (typeof(TValue) == typeof(int))
- return cil.Create(OpCodes.Ldc_I4, (int)value);
- if (typeof(TValue) == typeof(string))
- return cil.Create(OpCodes.Ldstr, (string)value);
- throw new NotSupportedException($"Rewriting to constant values of type {typeof(TValue)} isn't currently supported.");
- }
- }
-}
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
index c2120444..ad5cb96f 100644
--- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs
@@ -35,11 +35,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
this.ShouldIgnore = shouldIgnore;
}
- /// <summary>Rewrite a type reference if needed.</summary>
- /// <param name="module">The assembly module containing the instruction.</param>
- /// <param name="type">The type definition to handle.</param>
- /// <param name="replaceWith">Replaces the type reference with a new one.</param>
- /// <returns>Returns whether the type was changed.</returns>
+ /// <inheritdoc />
public override bool Handle(ModuleDefinition module, TypeReference type, Action<TypeReference> replaceWith)
{
// check type reference