瀏覽代碼

Keep track of MethodInfoFunctionInstance's target object (#1658)

Marko Lahma 1 年之前
父節點
當前提交
5ee35f1e52

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

@@ -3331,5 +3331,14 @@ try {
             var result = engine.Evaluate("const strings = Utils.GetStrings(); strings.Count;").AsNumber();
             Assert.Equal(3, result);
         }
+
+        [Fact]
+        public void CanDestructureInteropTargetMethod()
+        {
+            var engine = new Engine();
+            engine.SetValue("test", new Utils());
+            var result = engine.Evaluate("const { getStrings } = test; getStrings().Count;");
+            Assert.Equal(3, result);
+        }
     }
 }

+ 1 - 1
Jint/Native/Error/ErrorInstance.cs

@@ -31,6 +31,6 @@ public class ErrorInstance : ObjectInstance
 
     public override string ToString()
     {
-        return Engine.Realm.Intrinsics.Error.PrototypeObject.ToString(this, Arguments.Empty).ToObject().ToString() ?? "";
+        return Engine.Realm.Intrinsics.Error.PrototypeObject.ToString(this, Arguments.Empty).ToObject()?.ToString() ?? "";
     }
 }

+ 1 - 1
Jint/Native/JsNull.cs

@@ -8,7 +8,7 @@ public sealed class JsNull : JsValue, IEquatable<JsNull>
     {
     }
 
-    public override object ToObject() => null!;
+    public override object? ToObject() => null;
 
     public override string ToString() => "null";
 

+ 1 - 1
Jint/Native/JsUndefined.cs

@@ -8,7 +8,7 @@ public sealed class JsUndefined : JsValue, IEquatable<JsUndefined>
     {
     }
 
-    public override object ToObject() => null!;
+    public override object? ToObject() => null;
 
     public override string ToString() => "undefined";
 

+ 1 - 1
Jint/Native/JsValue.cs

@@ -157,7 +157,7 @@ namespace Jint.Native
         /// Converts a <see cref="JsValue"/> to its underlying CLR value.
         /// </summary>
         /// <returns>The underlying CLR value of the <see cref="JsValue"/> instance.</returns>
-        public abstract object ToObject();
+        public abstract object? ToObject();
 
         /// <summary>
         /// Coerces boolean value from <see cref="JsValue"/> instance.

+ 8 - 2
Jint/Options.cs

@@ -169,10 +169,16 @@ namespace Jint
 
             foreach (var overloads in methods.GroupBy(x => x.Name))
             {
-                string name = overloads.Key;
                 PropertyDescriptor CreateMethodInstancePropertyDescriptor(ClrFunctionInstance? function)
                 {
-                    var instance = new MethodInfoFunctionInstance(engine, objectType, name, MethodDescriptor.Build(overloads.ToList()), function);
+                    var instance = new MethodInfoFunctionInstance(
+                        engine,
+                        objectType,
+                        target: null,
+                        overloads.Key,
+                        methods: MethodDescriptor.Build(overloads.ToList()),
+                        function);
+
                     return new PropertyDescriptor(instance, PropertyFlag.AllForbidden);
                 }
 

+ 8 - 5
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -10,6 +10,7 @@ namespace Jint.Runtime.Interop
     internal sealed class MethodInfoFunctionInstance : FunctionInstance
     {
         private readonly Type _targetType;
+        private readonly object? _target;
         private readonly string _name;
         private readonly MethodDescriptor[] _methods;
         private readonly ClrFunctionInstance? _fallbackClrFunctionInstance;
@@ -17,19 +18,21 @@ namespace Jint.Runtime.Interop
         public MethodInfoFunctionInstance(
             Engine engine,
             Type targetType,
+            object? target,
             string name,
             MethodDescriptor[] methods,
             ClrFunctionInstance? fallbackClrFunctionInstance = null)
             : base(engine, engine.Realm, new JsString(name))
         {
             _targetType = targetType;
+            _target = target;
             _name = name;
             _methods = methods;
             _fallbackClrFunctionInstance = fallbackClrFunctionInstance;
             _prototype = engine.Realm.Intrinsics.Function.PrototypeObject;
         }
 
-        private static bool IsGenericParameter(object argObj, Type parameterType)
+        private static bool IsGenericParameter(object? argObj, Type parameterType)
         {
             if (argObj is null)
             {
@@ -49,7 +52,7 @@ namespace Jint.Runtime.Interop
             return false;
         }
 
-        private static void HandleGenericParameter(object argObj, Type parameterType, Type[] genericArgTypes)
+        private static void HandleGenericParameter(object? argObj, Type parameterType, Type[] genericArgTypes)
         {
             if (argObj is null)
             {
@@ -94,7 +97,7 @@ namespace Jint.Runtime.Interop
             }
         }
 
-        private static MethodBase ResolveMethod(MethodBase method, ParameterInfo[] methodParameters, object thisObj, JsValue[] arguments)
+        private static MethodBase ResolveMethod(MethodBase method, ParameterInfo[] methodParameters, JsValue[] arguments)
         {
             if (!method.IsGenericMethod)
             {
@@ -156,7 +159,7 @@ namespace Jint.Runtime.Interop
             }
 
             var converter = Engine.ClrTypeConverter;
-            var thisObj = thisObject.ToObject();
+            var thisObj = thisObject.ToObject() ?? _target;
             object?[]? parameters = null;
             foreach (var (method, arguments, _) in TypeConverter.FindBestMatch(_engine, _methods, ArgumentProvider))
             {
@@ -167,7 +170,7 @@ namespace Jint.Runtime.Interop
                 }
 
                 var argumentsMatch = true;
-                var resolvedMethod = ResolveMethod(method.Method, methodParameters, thisObj, arguments);
+                var resolvedMethod = ResolveMethod(method.Method, methodParameters, arguments);
                 // TPC: if we're concerned about cost of MethodInfo.GetParameters() - we could only invoke it if this ends up being a generic method (i.e. they will be different in that scenario)
                 methodParameters = resolvedMethod.GetParameters();
                 for (var i = 0; i < parameters.Length; i++)

+ 1 - 1
Jint/Runtime/Interop/Reflection/MethodAccessor.cs

@@ -24,7 +24,7 @@ namespace Jint.Runtime.Interop.Reflection
 
         public override PropertyDescriptor CreatePropertyDescriptor(Engine engine, object target, bool enumerable = true)
         {
-            return new(new MethodInfoFunctionInstance(engine, _targetType, _name, _methods), PropertyFlag.AllForbidden);
+            return new(new MethodInfoFunctionInstance(engine, _targetType, target, _name, _methods), PropertyFlag.AllForbidden);
         }
     }
 }