Skip to content

Commit

Permalink
Interface type wrapper can call object methods. (#1629)
Browse files Browse the repository at this point in the history
Fix #1626
  • Loading branch information
viruscamp authored Aug 31, 2023
1 parent 9dd7927 commit d48ebd5
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 5 deletions.
60 changes: 57 additions & 3 deletions Jint.Tests/Runtime/InteropExplicitTypeTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Jint.Tests.Runtime;

using Jint.Native;
using Jint.Runtime.Interop;

public class InteropExplicitTypeTests
Expand Down Expand Up @@ -154,9 +155,9 @@ public NullabeStruct()
}
public string name = "NullabeStruct";

public string Name { get => name; }
public string Name => name;

string I1.Name { get => "NullabeStruct as I1"; }
string I1.Name => "NullabeStruct as I1";
}

public class NullableHolder
Expand All @@ -172,7 +173,7 @@ public void TypedObjectWrapperForNullableType()
_engine.SetValue("nullableHolder", nullableHolder);
_engine.SetValue("nullabeStruct", new NullabeStruct());

Assert.Equal(_engine.Evaluate("nullableHolder.NullabeStruct"), Native.JsValue.Null);
Assert.Equal(_engine.Evaluate("nullableHolder.NullabeStruct"), JsValue.Null);
_engine.Evaluate("nullableHolder.NullabeStruct = nullabeStruct");
Assert.Equal(_engine.Evaluate("nullableHolder.NullabeStruct.Name"), nullableHolder.NullabeStruct?.Name);
}
Expand Down Expand Up @@ -288,4 +289,57 @@ public void ClrHelperObjectToType()
});
Assert.Equal("Invalid when Engine.Options.Interop.AllowGetType == false", ex.Message);
}

public interface ICallObjectMethodFromInterface
{
ICallObjectMethodFromInterface Instance { get; }
// hide Object.GetHashCode
string GetHashCode();
// overload Object.Equals
string Equals();
}
public class CallObjectMethodFromInterface : ICallObjectMethodFromInterface
{
public ICallObjectMethodFromInterface Instance => this;
public override string ToString() => nameof(CallObjectMethodFromInterface);
public new string GetHashCode() => "new GetHashCode, hide Object.GetHashCode";
public string Equals() => "overload Object.Equals";
}

// issue#1626 ToString method is now unavailable in some CLR Interop scenarios
[Fact]
public void CallObjectMethodFromInterfaceWrapper()
{
var inst = new CallObjectMethodFromInterface();
_engine.SetValue("inst", inst);
Assert.Equal(inst.Instance.ToString(), _engine.Evaluate("inst.Instance.ToString()"));
}

[Fact]
public void CallInterfaceMethodWhichHideObjectMethod()
{
var inst = new CallObjectMethodFromInterface();
_engine.SetValue("inst", inst);
Assert.Equal(inst.Instance.GetHashCode(), _engine.Evaluate("inst.Instance.GetHashCode()"));
}

[Fact(Skip = "TODO, no solution now.")]
public void CallObjectMethodHiddenByInterface()
{
var inst = new CallObjectMethodFromInterface();
_engine.SetValue("inst", inst);
Assert.Equal(
(inst.Instance as object).GetHashCode(),
_engine.Evaluate("clrHelper.unwrap(inst.Instance).GetHashCode()")
);
}

[Fact]
public void CallInterfaceMethodWhichOverloadObjectMethod()
{
var inst = new CallObjectMethodFromInterface();
_engine.SetValue("inst", inst);
Assert.Equal(inst.Instance.Equals(), _engine.Evaluate("inst.Instance.Equals()"));
Assert.Equal(inst.Instance.Equals(inst), _engine.Evaluate("inst.Instance.Equals(inst)"));
}
}
17 changes: 15 additions & 2 deletions Jint/Runtime/Interop/TypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,11 @@ internal bool TryFindMemberAccessor(

// if no properties were found then look for a method
List<MethodInfo>? methods = null;
foreach (var m in type.GetMethods(bindingFlags))
void AddMethod(MethodInfo m)
{
if (!Filter(engine, m))
{
continue;
return;
}

foreach (var name in typeResolverMemberNameCreator(m))
Expand All @@ -283,6 +283,10 @@ internal bool TryFindMemberAccessor(
}
}
}
foreach (var m in type.GetMethods(bindingFlags))
{
AddMethod(m);
}

// TPC: need to grab the extension methods here - for overloads
if (engine._extensionMethods.TryGetExtensionMethods(type, out var extensionMethods))
Expand All @@ -297,6 +301,15 @@ internal bool TryFindMemberAccessor(
}
}

// Add Object methods to interface
if (type.IsInterface)
{
foreach (var m in typeof(object).GetMethods(bindingFlags))
{
AddMethod(m);
}
}

if (methods?.Count > 0)
{
accessor = new MethodAccessor(type, memberName, MethodDescriptor.Build(methods));
Expand Down

0 comments on commit d48ebd5

Please sign in to comment.