diff options
-rw-r--r-- | src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs | 30 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/RewriteHelper.cs | 43 |
2 files changed, 39 insertions, 34 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs index 47c8b33c..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 @@ -65,12 +61,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders return InstructionHandleResult.None; // validate return type - string actualReturnTypeID = this.GetComparableTypeID(targetField.FieldType); - string expectedReturnTypeID = this.GetComparableTypeID(fieldRef.FieldType); - - if (!RewriteHelper.LooksLikeSameType(expectedReturnTypeID, actualReturnTypeID)) + 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; } } @@ -92,10 +85,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders return InstructionHandleResult.NotCompatible; } - string expectedReturnType = this.GetComparableTypeID(methodDef.ReturnType); - if (candidateMethods.All(method => !RewriteHelper.LooksLikeSameType(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; } } @@ -114,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) @@ -141,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/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/RewriteHelper.cs index 1600069d..f8684cde 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteHelper.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteHelper.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; @@ -11,6 +12,13 @@ namespace StardewModdingAPI.Framework.ModLoading internal static class RewriteHelper { /********* + ** Properties + *********/ + /// <summary>A pattern matching type name substrings to strip for display.</summary> + private static readonly Regex StripTypeNamePattern = new Regex(@"`\d+(?=<)", RegexOptions.Compiled); + + + /********* ** Public methods *********/ /// <summary>Get the field reference from an instruction if it matches.</summary> @@ -109,29 +117,39 @@ namespace StardewModdingAPI.Framework.ModLoading } /// <summary>Determine whether two type IDs look like the same type, accounting for placeholder values such as !0.</summary> - /// <param name="typeA">The type ID to compare.</param> - /// <param name="typeB">The other type ID to compare.</param> + /// <param name="a">The type ID to compare.</param> + /// <param name="b">The other type ID to compare.</param> /// <returns>true if the type IDs look like the same type, false if not.</returns> - public static bool LooksLikeSameType(string typeA, string typeB) + public static bool LooksLikeSameType(TypeReference a, TypeReference b) { + string typeA = RewriteHelper.GetComparableTypeID(a); + string typeB = RewriteHelper.GetComparableTypeID(b); + string placeholderType = "", actualType = ""; if (RewriteHelper.HasPlaceholder(typeA)) { placeholderType = typeA; actualType = typeB; - } else if (RewriteHelper.HasPlaceholder(typeB)) + } + else if (RewriteHelper.HasPlaceholder(typeB)) { placeholderType = typeB; actualType = typeA; - } else - { - return typeA == typeB; } + else + return typeA == typeB; return RewriteHelper.PlaceholderTypeValidates(placeholderType, actualType); } + /// <summary>Get a unique string representation of a type.</summary> + /// <param name="type">The type reference.</param> + private static string GetComparableTypeID(TypeReference type) + { + return RewriteHelper.StripTypeNamePattern.Replace(type.FullName, ""); + } + protected class SymbolLocation { public string symbol; @@ -144,7 +162,7 @@ namespace StardewModdingAPI.Framework.ModLoading } } - private static List<char> symbolBoundaries = new List<char>{'<', '>', ','}; + private static List<char> symbolBoundaries = new List<char> { '<', '>', ',' }; /// <summary> Traverses and parses out symbols from a type which does not contain placeholder values.</summary> /// <param name="type">The type to traverse.</param> @@ -160,7 +178,8 @@ namespace StardewModdingAPI.Framework.ModLoading { typeSymbols.Add(new SymbolLocation(symbol, depth)); symbol = ""; - switch (c) { + switch (c) + { case '<': depth++; break; @@ -186,7 +205,8 @@ namespace StardewModdingAPI.Framework.ModLoading if (symbolA.depth != symbolB.depth) return false; - if (!RewriteHelper.IsPlaceholder(symbolA.symbol)) { + if (!RewriteHelper.IsPlaceholder(symbolA.symbol)) + { return symbolA.symbol == symbolB.symbol; } @@ -245,7 +265,8 @@ namespace StardewModdingAPI.Framework.ModLoading /// <param name="placeholderType">The type with placeholders in it.</param> /// <param name="actualType">The type without placeholders.</param> /// <returns>true if the placeholder type can resolve to the actual type, false if not.</returns> - private static bool PlaceholderTypeValidates(string placeholderType, string actualType) { + private static bool PlaceholderTypeValidates(string placeholderType, string actualType) + { List<SymbolLocation> typeSymbols = new List<SymbolLocation>(); RewriteHelper.TraverseActualType(actualType, typeSymbols); |