Răsfoiți Sursa

Improve enum overload matching and interop (#843)

Marko Lahma 4 ani în urmă
părinte
comite
807ce1e26e

+ 14 - 0
Jint.Tests/Runtime/Domain/Enums.cs

@@ -0,0 +1,14 @@
+namespace Jint.Tests.Runtime.Domain
+{
+    public enum IntegerEnum
+    {
+        a,
+        b
+    }   
+    
+    public enum UintEnum : uint
+    {
+        a, 
+        b
+    }
+}

+ 20 - 0
Jint.Tests/Runtime/Domain/OverLoading.cs

@@ -0,0 +1,20 @@
+namespace Jint.Tests.Runtime.Domain
+{
+    public class OverLoading
+    {
+        public string TestFunc(string e)
+        {
+            return "string";
+        }
+
+        public string TestFunc(IntegerEnum e)
+        {
+            return "integer-enum";
+        }
+
+        public string TestFunc(UintEnum e)
+        {
+            return "uint-enum";
+        }
+    }
+}

+ 17 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -2356,5 +2356,22 @@ namespace Jint.Tests.Runtime
                 return true;
             }
         }
+            
+        [Fact]
+        public void IntegerEnumResolutionShouldWork()
+        {
+            var engine = new Engine(options => options.AllowClr(GetType().Assembly));
+            engine.SetValue("a", new OverLoading());
+            engine.SetValue("E", TypeReference.CreateTypeReference(engine, typeof(IntegerEnum)));
+            Assert.Equal("integer-enum", engine.Execute("a.testFunc(E.a);").GetCompletionValue().AsString());
+        }
+
+        [Fact]
+        public void UnsignedIntegerEnumResolutionShouldWork()
+        {
+            var engine = new Engine(options => options.AllowClr(GetType().Assembly));
+            engine.SetValue("E", TypeReference.CreateTypeReference(engine, typeof(UintEnum)));
+            Assert.Equal(1, engine.Execute("E.b;").GetCompletionValue().AsNumber());
+        }
     }
 }

+ 17 - 0
Jint/Native/JsNumber.cs

@@ -72,6 +72,23 @@ namespace Jint.Native
             return _value;
         }
 
+        internal static JsNumber Create(object value)
+        {
+            var underlyingType = System.Type.GetTypeCode(Enum.GetUnderlyingType(value.GetType()));
+            switch (underlyingType)
+            {
+                case TypeCode.Int64:
+                    return Create(Convert.ToInt64(value));
+
+                case TypeCode.UInt32:
+                case TypeCode.UInt64:
+                    return Create(Convert.ToUInt64(value));
+
+                default:
+                    return Create(Convert.ToInt32(value));
+            }
+        }
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal static JsNumber Create(double value)
         {

+ 2 - 1
Jint/Runtime/Interop/TypeReference.cs

@@ -183,7 +183,8 @@ namespace Jint.Runtime.Interop
                 {
                     if (enumNames.GetValue(i) as string == name)
                     {
-                        return new ConstantValueAccessor((int) enumValues.GetValue(i));
+                        var value = enumValues.GetValue(i);
+                        return new ConstantValueAccessor(JsNumber.Create(value));
                     }
                 }
 

+ 16 - 3
Jint/Runtime/TypeConverter.cs

@@ -611,7 +611,8 @@ namespace Jint.Runtime
                 var arguments = tuple.Item2;
                 for (var i = 0; i < arguments.Length; i++)
                 {
-                    var arg = arguments[i].ToObject();
+                    var jsValue = arguments[i];
+                    var arg = jsValue.ToObject();
                     var paramType = parameters[i].ParameterType;
                     if (arg == null)
                     {
@@ -623,8 +624,20 @@ namespace Jint.Runtime
                     }
                     else if (arg.GetType() != paramType)
                     {
-                        perfectMatch = false;
-                        break;
+                        // check if we can do conversion from int value to enum
+                        if (paramType.IsEnum && 
+                            jsValue is JsNumber jsNumber
+                            && jsNumber.IsInteger()
+                            && Enum.IsDefined(paramType, jsNumber.AsInteger()))
+                        {
+                            // OK
+                        }
+                        else
+                        {
+                            // no can do
+                            perfectMatch = false;
+                            break;
+                        }
                     }
                 }