diff --git a/Jint.Tests/Runtime/InteropTests.cs b/Jint.Tests/Runtime/InteropTests.cs index 43fcc01ab..8f383e985 100644 --- a/Jint.Tests/Runtime/InteropTests.cs +++ b/Jint.Tests/Runtime/InteropTests.cs @@ -3297,9 +3297,13 @@ private class Container public BaseClass Get() => _child; } - private class BaseClass { } + private class BaseClass + { + } - private class Child : BaseClass { } + private class Child : BaseClass + { + } [Fact] public void AccessingBaseTypeShouldBeEqualToAccessingDerivedType() @@ -3328,6 +3332,7 @@ public interface IStringCollection : IIndexer, ICountable public class Strings : IStringCollection { private readonly string[] _strings; + public Strings(string[] strings) { _strings = strings; @@ -3340,7 +3345,7 @@ public Strings(string[] strings) public class Utils { - public IStringCollection GetStrings() => new Strings(new [] { "a", "b", "c" }); + public IStringCollection GetStrings() => new Strings(new[] { "a", "b", "c" }); } [Fact] @@ -3384,6 +3389,7 @@ private class MetadataWrapper : IDictionary public bool ContainsKey(string key) => throw new NotImplementedException(); public void Add(string key, object value) => throw new NotImplementedException(); public bool Remove(string key) => throw new NotImplementedException(); + public bool TryGetValue(string key, out object value) { value = "from-wrapper"; @@ -3467,6 +3473,7 @@ public void ShouldRespectConcreteGenericReturnTypes() }); var result = new List(); + void Debug(object o) { result.Add($"{o?.GetType().Name ?? "null"}: {o ?? "null"}"); @@ -3487,73 +3494,97 @@ void Debug(object o) private class ClrMembersVisibilityTestClass { - public int A { get; set; } = 10; + public string Field = "field"; - public int F() + public int Property { get; set; } = 10; + + public int Method() { return 4; } + + public string Extras { get; set; } } [Fact] - public void ShouldNotSeeClrMethods() + public void PropertiesShouldNotSeeReportMethodsWhenMemberTypesActive() { var engine = new Engine(opt => { opt.Interop.ObjectWrapperReportedMemberTypes = MemberTypes.Field | MemberTypes.Property; }); - + engine.SetValue("clrInstance", new ClrMembersVisibilityTestClass()); - - var val = engine.GetValue("clrInstance"); - var obj = val.AsObject(); - var props = obj.GetOwnProperties().Select(x => x.Key.ToString()).ToList(); - - props.Should().BeEquivalentTo(["A"]); + var val = engine.GetValue("clrInstance"); + + var obj = val.AsObject(); + var props = obj.GetOwnProperties().Select(x => x.Key.ToString()).ToList(); + + props.Should().BeEquivalentTo("Property", "Extras", "Field"); } - + [Fact] - public void ShouldSeeClrMethods() + public void PropertyKeysShouldReportMethods() { var engine = new Engine(); - + + engine.SetValue("clrInstance", new ClrMembersVisibilityTestClass()); + + var val = engine.GetValue("clrInstance"); + var obj = val.AsObject(); + var props = obj.GetOwnProperties().Select(x => x.Key.ToString()).ToList(); + + props.Should().BeEquivalentTo("Property", "Extras", "Field", "Method"); + } + + [Fact] + public void PropertyKeysShouldObeyMemberFilter() + { + var engine = new Engine(options => + { + options.SetTypeResolver(new TypeResolver + { + MemberFilter = member => member.Name == "Extras" + }); + }); + engine.SetValue("clrInstance", new ClrMembersVisibilityTestClass()); - + var val = engine.GetValue("clrInstance"); var obj = val.AsObject(); var props = obj.GetOwnProperties().Select(x => x.Key.ToString()).ToList(); - props.Should().BeEquivalentTo(["A", "F"]); + props.Should().BeEquivalentTo("Extras"); } - + private class ClrMembersVisibilityTestClass2 { public int Get_A { get; set; } = 5; } - + [Fact] public void ShouldSeeClrMethods2() { var engine = new Engine(); - + engine.SetValue("clrInstance", new ClrMembersVisibilityTestClass2()); - + var val = engine.GetValue("clrInstance"); var obj = val.AsObject(); var props = obj.GetOwnProperties().Select(x => x.Key.ToString()).ToList(); - - props.Should().BeEquivalentTo(["Get_A"]); + + props.Should().BeEquivalentTo("Get_A"); } - + [Fact] public void ShouldNotThrowOnInspectingClrFunction() { var engine = new Engine(); - + engine.SetValue("clrDelegate", () => 4); - + var val = engine.GetValue("clrDelegate"); var fn = val as Function; @@ -3561,7 +3592,7 @@ public void ShouldNotThrowOnInspectingClrFunction() decl.Should().BeNull(); } - + private class ShouldNotThrowOnInspectingClrFunctionTestClass { public int MyInt() @@ -3569,20 +3600,20 @@ public int MyInt() return 4; } } - + [Fact] public void ShouldNotThrowOnInspectingClrClassFunction() { var engine = new Engine(); - + engine.SetValue("clrCls", new ShouldNotThrowOnInspectingClrFunctionTestClass()); - + var val = engine.GetValue("clrCls"); var clrFn = val.Get("MyInt"); - + var fn = clrFn as Function; var decl = fn!.FunctionDeclaration; - + decl.Should().BeNull(); } @@ -3592,13 +3623,5 @@ public void StringifyShouldIncludeInheritedFieldsAndProperties() var engine = new Engine(); engine.SetValue("c", new Circle(12.34)); engine.Evaluate("JSON.stringify(c)").ToString().Should().Be("{\"Radius\":12.34,\"Color\":0,\"Id\":123}"); - - - engine = new Engine(options => - { - options.Interop.ObjectWrapperReportOnlyDeclaredMembers = true; - }); - engine.SetValue("c", new Circle(12.34)); - engine.Evaluate("JSON.stringify(c)").ToString().Should().Be("{\"Radius\":12.34}"); } } diff --git a/Jint/Native/Atomics/AtomicsInstance.cs b/Jint/Native/Atomics/AtomicsInstance.cs index 48bd202b6..96b3d993f 100644 --- a/Jint/Native/Atomics/AtomicsInstance.cs +++ b/Jint/Native/Atomics/AtomicsInstance.cs @@ -1,4 +1,3 @@ -using System.Numerics; using System.Threading; using Jint.Collections; using Jint.Native.Object; diff --git a/Jint/Options.cs b/Jint/Options.cs index 613bf3de9..1cee53c6c 100644 --- a/Jint/Options.cs +++ b/Jint/Options.cs @@ -371,13 +371,6 @@ public class InteropOptions /// All other values are ignored. /// public MemberTypes ObjectWrapperReportedMemberTypes { get; set; } = MemberTypes.Field | MemberTypes.Property | MemberTypes.Method; - - /// - /// Whether object wrapper should only report members that are declared on the object type itself, not inherited members. Defaults to false. - /// This is different from JS logic where only object's own members are reported and not prototypes. - /// - /// This configuration does not affect methods, only methods declared in type itself will be reported. - public bool ObjectWrapperReportOnlyDeclaredMembers { get; set; } } public class ConstraintOptions diff --git a/Jint/Runtime/Interop/ObjectWrapper.cs b/Jint/Runtime/Interop/ObjectWrapper.cs index 4328a39f0..6a53056ff 100644 --- a/Jint/Runtime/Interop/ObjectWrapper.cs +++ b/Jint/Runtime/Interop/ObjectWrapper.cs @@ -257,15 +257,16 @@ private IEnumerable EnumerateOwnPropertyKeys(Types types) // we take public properties, fields and methods var bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; - if (interopOptions.ObjectWrapperReportOnlyDeclaredMembers) - { - bindingFlags |= BindingFlags.DeclaredOnly; - } if ((interopOptions.ObjectWrapperReportedMemberTypes & MemberTypes.Property) == MemberTypes.Property) { foreach (var p in ClrType.GetProperties(bindingFlags)) { + if (!interopOptions.TypeResolver.Filter(_engine, ClrType, p)) + { + continue; + } + var indexParameters = p.GetIndexParameters(); if (indexParameters.Length == 0) { @@ -278,15 +279,21 @@ private IEnumerable EnumerateOwnPropertyKeys(Types types) { foreach (var f in ClrType.GetFields(bindingFlags)) { + if (!interopOptions.TypeResolver.Filter(_engine, ClrType, f)) + { + continue; + } + yield return JsString.Create(f.Name); } } if ((interopOptions.ObjectWrapperReportedMemberTypes & MemberTypes.Method) == MemberTypes.Method) { - foreach (var m in ClrType.GetMethods(bindingFlags | BindingFlags.DeclaredOnly)) + foreach (var m in ClrType.GetMethods(bindingFlags)) { - if (m.IsSpecialName) + // we won't report anything from base object as it would usually not be something to expect from JS perspective + if (m.DeclaringType == typeof(object) || m.IsSpecialName || !interopOptions.TypeResolver.Filter(_engine, ClrType, m)) { continue; } diff --git a/Jint/Runtime/Interop/Reflection/DynamicObjectAccessor.cs b/Jint/Runtime/Interop/Reflection/DynamicObjectAccessor.cs index 8244acf44..608f1edb0 100644 --- a/Jint/Runtime/Interop/Reflection/DynamicObjectAccessor.cs +++ b/Jint/Runtime/Interop/Reflection/DynamicObjectAccessor.cs @@ -1,5 +1,4 @@ using System.Dynamic; -using System.Reflection; using Jint.Native; #pragma warning disable IL2092