summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2018-03-05 19:07:22 -0500
committerJesse Plamondon-Willard <github@jplamondonw.com>2018-03-05 19:07:22 -0500
commit8689fe65642d07fa6a2513aa36c1389479e50d0c (patch)
tree65e2055edc73c354b1995bcae96c5339fbd61e5c
parent1fbd41ecb2141d769072c71822fb02876401a592 (diff)
downloadSMAPI-8689fe65642d07fa6a2513aa36c1389479e50d0c.tar.gz
SMAPI-8689fe65642d07fa6a2513aa36c1389479e50d0c.tar.bz2
SMAPI-8689fe65642d07fa6a2513aa36c1389479e50d0c.zip
fix compatibility heuristics incorrectly flagging mods with missing optional references (#453)
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs22
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs26
-rw-r--r--src/SMAPI/Metadata/InstructionMetadata.cs12
3 files changed, 54 insertions, 6 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
index 0e7344a8..b5e45742 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Mono.Cecil;
@@ -12,6 +13,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/*********
** Properties
*********/
+ /// <summary>The assembly names to which to heuristically detect broken references.</summary>
+ private readonly HashSet<string> ValidateReferencesToAssemblies;
+
/// <summary>A pattern matching type name substrings to strip for display.</summary>
private readonly Regex StripTypeNamePattern = new Regex(@"`\d+(?=<)", RegexOptions.Compiled);
@@ -26,6 +30,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/*********
** Public methods
*********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="validateReferencesToAssemblies">The assembly names to which to heuristically detect broken references.</param>
+ public ReferenceToMemberWithUnexpectedTypeFinder(string[] validateReferencesToAssemblies)
+ {
+ this.ValidateReferencesToAssemblies = new HashSet<string>(validateReferencesToAssemblies);
+ }
+
/// <summary>Perform the predefined logic for a method if applicable.</summary>
/// <param name="module">The assembly module containing the instruction.</param>
/// <param name="method">The method definition containing the instruction.</param>
@@ -46,7 +57,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
{
// field reference
FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
- if (fieldRef != null)
+ if (fieldRef != null && this.ShouldValidate(fieldRef.DeclaringType))
{
// can't compare generic type parameters between definition and reference
if (fieldRef.FieldType.IsGenericInstance || fieldRef.FieldType.IsGenericParameter)
@@ -69,7 +80,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
// method reference
MethodReference methodReference = RewriteHelper.AsMethodReference(instruction);
- if (methodReference != null)
+ if (methodReference != null && this.ShouldValidate(methodReference.DeclaringType))
{
// can't compare generic type parameters between definition and reference
if (methodReference.ReturnType.IsGenericInstance || methodReference.ReturnType.IsGenericParameter)
@@ -103,6 +114,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/*********
** 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.ValidateReferencesToAssemblies.Contains(type.Scope.Name);
+ }
+
/// <summary>Get a unique string representation of a type.</summary>
/// <param name="type">The type reference.</param>
private string GetComparableTypeID(TypeReference type)
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
index 60373c9d..f5e33313 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -9,6 +10,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
internal class ReferenceToMissingMemberFinder : IInstructionHandler
{
/*********
+ ** Properties
+ *********/
+ /// <summary>The assembly names to which to heuristically detect broken references.</summary>
+ private readonly HashSet<string> ValidateReferencesToAssemblies;
+
+
+ /*********
** Accessors
*********/
/// <summary>A brief noun phrase indicating what the instruction finder matches.</summary>
@@ -18,6 +26,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/*********
** Public methods
*********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="validateReferencesToAssemblies">The assembly names to which to heuristically detect broken references.</param>
+ public ReferenceToMissingMemberFinder(string[] validateReferencesToAssemblies)
+ {
+ this.ValidateReferencesToAssemblies = new HashSet<string>(validateReferencesToAssemblies);
+ }
+
/// <summary>Perform the predefined logic for a method if applicable.</summary>
/// <param name="module">The assembly module containing the instruction.</param>
/// <param name="method">The method definition containing the instruction.</param>
@@ -38,7 +53,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
{
// field reference
FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
- if (fieldRef != null)
+ if (fieldRef != null && this.ShouldValidate(fieldRef.DeclaringType))
{
FieldDefinition target = fieldRef.DeclaringType.Resolve()?.Fields.FirstOrDefault(p => p.Name == fieldRef.Name);
if (target == null)
@@ -50,7 +65,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
// method reference
MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
- if (methodRef != null && !this.IsUnsupported(methodRef))
+ if (methodRef != null && this.ShouldValidate(methodRef.DeclaringType) && !this.IsUnsupported(methodRef))
{
MethodDefinition target = methodRef.DeclaringType.Resolve()?.Methods.FirstOrDefault(p => p.Name == methodRef.Name);
if (target == null)
@@ -69,6 +84,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/*********
** 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.ValidateReferencesToAssemblies.Contains(type.Scope.Name);
+ }
+
/// <summary>Get whether a method reference is a special case that's not currently supported (e.g. array methods).</summary>
/// <param name="method">The method reference.</param>
private bool IsUnsupported(MethodReference method)
diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs
index 9e2b7967..4ed1e38e 100644
--- a/src/SMAPI/Metadata/InstructionMetadata.cs
+++ b/src/SMAPI/Metadata/InstructionMetadata.cs
@@ -13,6 +13,14 @@ namespace StardewModdingAPI.Metadata
internal class InstructionMetadata
{
/*********
+ ** Properties
+ *********/
+ /// <summary>The assembly names to which to heuristically detect broken references.</summary>
+ /// <remarks>The current implementation only works correctly with assemblies that should always be present.</remarks>
+ private readonly string[] ValidateReferencesToAssemblies = { "StardewModdingAPI", "Stardew Valley", "StardewValley" };
+
+
+ /*********
** Public methods
*********/
/// <summary>Get rewriters which detect or fix incompatible CIL instructions in mod assemblies.</summary>
@@ -87,8 +95,8 @@ namespace StardewModdingAPI.Metadata
new PropertyFinder("StardewModdingAPI.Mod", "PerSaveConfigPath", InstructionHandleResult.NotCompatible),
// broken code
- new ReferenceToMissingMemberFinder(),
- new ReferenceToMemberWithUnexpectedTypeFinder(),
+ new ReferenceToMissingMemberFinder(this.ValidateReferencesToAssemblies),
+ new ReferenceToMemberWithUnexpectedTypeFinder(this.ValidateReferencesToAssemblies),
/****
** detect code which may impact game stability