summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModLoading/Finders
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework/ModLoading/Finders')
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs37
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs11
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs10
3 files changed, 22 insertions, 36 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
index b5e45742..cf5a3175 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Linq;
-using System.Text.RegularExpressions;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -16,9 +15,6 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <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);
-
/*********
** Accessors
@@ -59,21 +55,15 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);
if (fieldRef != null && this.ShouldValidate(fieldRef.DeclaringType))
{
- // can't compare generic type parameters between definition and reference
- if (fieldRef.FieldType.IsGenericInstance || fieldRef.FieldType.IsGenericParameter)
- return InstructionHandleResult.None;
-
// get target field
FieldDefinition targetField = fieldRef.DeclaringType.Resolve()?.Fields.FirstOrDefault(p => p.Name == fieldRef.Name);
if (targetField == null)
return InstructionHandleResult.None;
// validate return type
- string actualReturnTypeID = this.GetComparableTypeID(targetField.FieldType);
- string expectedReturnTypeID = this.GetComparableTypeID(fieldRef.FieldType);
- if (actualReturnTypeID != expectedReturnTypeID)
+ if (!RewriteHelper.LooksLikeSameType(fieldRef.FieldType, targetField.FieldType))
{
- this.NounPhrase = $"reference to {fieldRef.DeclaringType.FullName}.{fieldRef.Name} (field returns {this.GetFriendlyTypeName(targetField.FieldType, actualReturnTypeID)}, not {this.GetFriendlyTypeName(fieldRef.FieldType, expectedReturnTypeID)})";
+ this.NounPhrase = $"reference to {fieldRef.DeclaringType.FullName}.{fieldRef.Name} (field returns {this.GetFriendlyTypeName(targetField.FieldType)}, not {this.GetFriendlyTypeName(fieldRef.FieldType)})";
return InstructionHandleResult.NotCompatible;
}
}
@@ -82,10 +72,6 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
MethodReference methodReference = RewriteHelper.AsMethodReference(instruction);
if (methodReference != null && this.ShouldValidate(methodReference.DeclaringType))
{
- // can't compare generic type parameters between definition and reference
- if (methodReference.ReturnType.IsGenericInstance || methodReference.ReturnType.IsGenericParameter)
- return InstructionHandleResult.None;
-
// get potential targets
MethodDefinition[] candidateMethods = methodReference.DeclaringType.Resolve()?.Methods.Where(found => found.Name == methodReference.Name).ToArray();
if (candidateMethods == null || !candidateMethods.Any())
@@ -99,10 +85,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
return InstructionHandleResult.NotCompatible;
}
- string expectedReturnType = this.GetComparableTypeID(methodDef.ReturnType);
- if (candidateMethods.All(method => this.GetComparableTypeID(method.ReturnType) != expectedReturnType))
+ if (candidateMethods.All(method => !RewriteHelper.LooksLikeSameType(method.ReturnType, methodDef.ReturnType)))
{
- this.NounPhrase = $"reference to {methodDef.DeclaringType.FullName}.{methodDef.Name} (no such method returns {this.GetFriendlyTypeName(methodDef.ReturnType, expectedReturnType)})";
+ this.NounPhrase = $"reference to {methodDef.DeclaringType.FullName}.{methodDef.Name} (no such method returns {this.GetFriendlyTypeName(methodDef.ReturnType)})";
return InstructionHandleResult.NotCompatible;
}
}
@@ -121,17 +106,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
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)
- {
- return this.StripTypeNamePattern.Replace(type.FullName, "");
- }
-
/// <summary>Get a shorter type name for display.</summary>
/// <param name="type">The type reference.</param>
- /// <param name="typeID">The comparable type ID from <see cref="GetComparableTypeID"/>.</param>
- private string GetFriendlyTypeName(TypeReference type, string typeID)
+ private string GetFriendlyTypeName(TypeReference type)
{
// most common built-in types
switch (type.FullName)
@@ -148,10 +125,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
foreach (string @namespace in new[] { "Microsoft.Xna.Framework", "Netcode", "System", "System.Collections.Generic" })
{
if (type.Namespace == @namespace)
- return typeID.Substring(@namespace.Length + 1);
+ return type.Name;
}
- return typeID;
+ return type.FullName;
}
}
}
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
index f5e33313..b95dd79c 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs
@@ -67,12 +67,15 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);
if (methodRef != null && this.ShouldValidate(methodRef.DeclaringType) && !this.IsUnsupported(methodRef))
{
- MethodDefinition target = methodRef.DeclaringType.Resolve()?.Methods.FirstOrDefault(p => p.Name == methodRef.Name);
+ MethodDefinition target = methodRef.Resolve();
if (target == null)
{
- this.NounPhrase = this.IsProperty(methodRef)
- ? $"reference to {methodRef.DeclaringType.FullName}.{methodRef.Name.Substring(4)} (no such property)"
- : $"reference to {methodRef.DeclaringType.FullName}.{methodRef.Name} (no such method)";
+ if (this.IsProperty(methodRef))
+ this.NounPhrase = $"reference to {methodRef.DeclaringType.FullName}.{methodRef.Name.Substring(4)} (no such property)";
+ else if (methodRef.Name == ".ctor")
+ this.NounPhrase = $"reference to {methodRef.DeclaringType.FullName}.{methodRef.Name} (no matching constructor)";
+ else
+ this.NounPhrase = $"reference to {methodRef.DeclaringType.FullName}.{methodRef.Name} (no such method)";
return InstructionHandleResult.NotCompatible;
}
}
diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
index 45349def..79045241 100644
--- a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
+++ b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs
@@ -1,3 +1,4 @@
+using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@@ -16,6 +17,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <summary>The result to return for matching instructions.</summary>
private readonly InstructionHandleResult Result;
+ /// <summary>A lambda which overrides a matched type.</summary>
+ protected readonly Func<TypeReference, bool> ShouldIgnore;
+
/*********
** Accessors
@@ -30,11 +34,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
/// <summary>Construct an instance.</summary>
/// <param name="fullTypeName">The full type name to match.</param>
/// <param name="result">The result to return for matching instructions.</param>
- public TypeFinder(string fullTypeName, InstructionHandleResult result)
+ /// <param name="shouldIgnore">A lambda which overrides a matched type.</param>
+ public TypeFinder(string fullTypeName, InstructionHandleResult result, Func<TypeReference, bool> shouldIgnore = null)
{
this.FullTypeName = fullTypeName;
this.Result = result;
this.NounPhrase = $"{fullTypeName} type";
+ this.ShouldIgnore = shouldIgnore ?? (p => false);
}
/// <summary>Perform the predefined logic for a method if applicable.</summary>
@@ -113,7 +119,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
protected bool IsMatch(TypeReference type)
{
// root type
- if (type.FullName == this.FullTypeName)
+ if (type.FullName == this.FullTypeName && !this.ShouldIgnore(type))
return true;
// generic arguments