Skip to content

Commit

Permalink
Include interface methods when searching for interop targets (#1638)
Browse files Browse the repository at this point in the history
Co-authored-by: hyzx86 <[email protected]>
Co-authored-by: Marko Lahma <[email protected]>
  • Loading branch information
3 people authored Sep 26, 2023
1 parent 29b67f8 commit da88d1e
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 5 deletions.
151 changes: 151 additions & 0 deletions Jint.Tests/Runtime/InteropInterfaceExtendTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
using Jint.Runtime;

namespace Jint.Tests.Runtime;

public class InterfaceTests
{
public interface I0
{
string NameI0 { get; }
string OverloadSuperMethod();
string SubPropertySuperMethod();
}

public interface I1 : I0
{
string Name { get; }
string OverloadSuperMethod(int x);
new string SubPropertySuperMethod { get; }
}

public class Super
{
public string Name { get; } = "Super";
}

public class CI1 : Super, I1
{
public new string Name { get; } = "CI1";

public string NameI0 { get; } = "I0.Name";

string I1.Name { get; } = "CI1 as I1";

string I1.SubPropertySuperMethod { get; } = "I1.SubPropertySuperMethod";

public string OverloadSuperMethod()
{
return "I0.OverloadSuperMethod()";
}

public string OverloadSuperMethod(int x)
{
return $"I1.OverloadSuperMethod(int {x})";
}

public string SubPropertySuperMethod()
{
return "I0.SubPropertySuperMethod()";
}
}

public class Indexer<T>
{
private readonly T t;

public Indexer(T t)
{
this.t = t;
}

public T this[int index]
{
get { return t; }
}
}

public class InterfaceHolder
{
public InterfaceHolder()
{
var ci1 = new CI1();
this.ci1 = ci1;
this.i1 = ci1;
this.super = ci1;

this.IndexerCI1 = new Indexer<CI1>(ci1);
this.IndexerI1 = new Indexer<I1>(ci1);
this.IndexerSuper = new Indexer<Super>(ci1);
}

public readonly CI1 ci1;
public readonly I1 i1;
public readonly Super super;

public CI1 CI1 { get => ci1; }
public I1 I1 { get => i1; }
public Super Super { get => super; }

public CI1 GetCI1() => ci1;
public I1 GetI1() => i1;
public Super GetSuper() => super;

public Indexer<CI1> IndexerCI1 { get; }
public Indexer<I1> IndexerI1 { get; }
public Indexer<Super> IndexerSuper { get; }
}

private readonly Engine _engine;
private readonly InterfaceHolder holder;

public InterfaceTests()
{
holder = new InterfaceHolder();
_engine = new Engine(cfg => cfg.AllowClr(
typeof(CI1).Assembly,
typeof(Console).Assembly,
typeof(File).Assembly))
.SetValue("log", new Action<object>(Console.WriteLine))
.SetValue("assert", new Action<bool>(Assert.True))
.SetValue("equal", new Action<object, object>(Assert.Equal))
.SetValue("holder", holder)
;
}

[Fact]
public void CallSuperPropertyFromInterface()
{
Assert.Equal(holder.I1.NameI0, _engine.Evaluate("holder.I1.NameI0"));
}

[Fact]
public void CallOverloadSuperMethod()
{
Assert.Equal(
holder.I1.OverloadSuperMethod(1),
_engine.Evaluate("holder.I1.OverloadSuperMethod(1)"));
Assert.Equal(
holder.I1.OverloadSuperMethod(),
_engine.Evaluate("holder.I1.OverloadSuperMethod()"));
}

[Fact]
public void CallSubPropertySuperMethod_SubProperty()
{
Assert.Equal(
holder.I1.SubPropertySuperMethod,
_engine.Evaluate("holder.I1.SubPropertySuperMethod"));
}

[Fact]
public void CallSubPropertySuperMethod_SuperMethod()
{
var ex = Assert.Throws<JavaScriptException>(() =>
{
Assert.Equal(
holder.I1.SubPropertySuperMethod(),
_engine.Evaluate("holder.I1.SubPropertySuperMethod()"));
});
Assert.Equal("Property 'SubPropertySuperMethod' of object is not a function", ex.Message);
}
}
15 changes: 10 additions & 5 deletions Jint/Runtime/Interop/TypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,21 +283,26 @@ void AddMethod(MethodInfo m)
}
}
}

foreach (var m in type.GetMethods(bindingFlags))
{
AddMethod(m);
}

foreach (var iface in type.GetInterfaces())
{
foreach (var m in iface.GetMethods())
{
AddMethod(m);
}
}

// TPC: need to grab the extension methods here - for overloads
if (engine._extensionMethods.TryGetExtensionMethods(type, out var extensionMethods))
{
foreach (var methodInfo in extensionMethods)
{
if (memberNameComparer.Equals(methodInfo.Name, memberName))
{
methods ??= new List<MethodInfo>();
methods.Add(methodInfo);
}
AddMethod(methodInfo);
}
}

Expand Down

0 comments on commit da88d1e

Please sign in to comment.