Skip to content

Commit

Permalink
Fixed proxy methods not accepting arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Yates committed Mar 31, 2021
1 parent 78116a8 commit 777a608
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 33 deletions.
70 changes: 53 additions & 17 deletions Shimterface.Tests/ExtendedFunctionalityTests.Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,37 @@ public interface ITestShim
}

[ExcludeFromCodeCoverage]
public class TestClass_NoMethodB
public class TestClass_OnlyMethodA
{
public TestClass_NoMethodB() { }
public TestClass_OnlyMethodA() { }

public bool MethodACalled { get; private set; }
public void MethodA()
{
MethodACalled = true;
}
}

[ExcludeFromCodeCoverage]
public class TestClass_HasMethodB
public class TestClass_HasMethodB : TestClass_OnlyMethodA
{
public bool MethodACalled { get; private set; }
public void MethodA()
{
MethodACalled = true;
}

public bool MethodBCalled { get; private set; }
public void MethodB()
{
MethodBCalled = true;
}
}

[ExcludeFromCodeCoverage]
public class TestClass_HasMethodC : TestClass_OnlyMethodA
{
public string MethodCCalledWith { get; private set; }
public void MethodC(string arg)
{
MethodCCalledWith = arg;
}
}

#region Override

public interface ITestShim_MethodOverride : ITestShim
Expand Down Expand Up @@ -264,6 +268,38 @@ public void Override_implementation_can_invoke_on_compatible_arg()
// Assert
Assert.AreSame(shim, TestImpl_ArgImpl.MethodBCalledObj);
}

public interface ITestShim_WithArg : ITestShim
{
[ShimProxy(typeof(TestImpl_WithArg))]
void MethodC(string arg);
}
[ExcludeFromCodeCoverage]
public class TestImpl_WithArg
{
public static string MethodCCalledWith { get; set; }
public static void MethodC(ITestShim obj, string arg)
{
obj.ToString();
MethodCCalledWith = arg;
}
}

[TestMethod]
public void Override_implementation_can_invoke_with_args()
{
// Arrange
var obj = new TestClass_HasMethodC();
var shim = obj.Shim<ITestShim_WithArg>();

// Act
obj.MethodC("test1");
shim.MethodC("test2");

// Assert
Assert.AreEqual("test1", obj.MethodCCalledWith);
Assert.AreEqual("test2", TestImpl_WithArg.MethodCCalledWith);
}

public interface ITestShim_MissingBase : ITestShim
{
Expand All @@ -283,7 +319,7 @@ public static void MethodB(ITestShim_MissingBase obj)
public void Override_member_must_exist_in_shimmed_type()
{
// Arrange
var obj = new TestClass_NoMethodB();
var obj = new TestClass_OnlyMethodA();

// Act
Assert.ThrowsException<InvalidCastException>(() =>
Expand Down Expand Up @@ -337,7 +373,7 @@ public static void MethodA(ITestShim_ChangeShim inst)
public void Can_change_shim_in_hierarchy()
{
// Arrange
var obj = new TestClass_NoMethodB();
var obj = new TestClass_OnlyMethodA();
var shim = obj.Shim<ITestShim_ChangeShim>();

// Act
Expand All @@ -350,7 +386,7 @@ public void Can_change_shim_in_hierarchy()

public interface ITestShim_Constructor
{
[ConstructorShim(typeof(TestClass_NoMethodB))]
[ConstructorShim(typeof(TestClass_OnlyMethodA))]
[ShimProxy(typeof(TestImpl_DefaultOverride))]
ITestShim MethodB();
}
Expand Down Expand Up @@ -387,7 +423,7 @@ public static void MethodB(ITestShim_MethodAdd obj)
public void Shim_can_define_proxy_to_add_member()
{
// Arrange
var obj = new TestClass_NoMethodB();
var obj = new TestClass_OnlyMethodA();
var shim = obj.Shim<ITestShim_MethodAdd>();

// Act
Expand Down Expand Up @@ -416,7 +452,7 @@ public static void MethodB(ITestShim_DefaultAdd obj)
public void Shim_can_define_proxy_to_add_member_by_default()
{
// Arrange
var obj = new TestClass_NoMethodB();
var obj = new TestClass_OnlyMethodA();
var shim = obj.Shim<ITestShim_DefaultAdd>();

// Act
Expand Down Expand Up @@ -445,7 +481,7 @@ public static void MethodD(ITestShim_MethodAddAlias obj)
public void Shim_can_define_proxy_to_add_member_to_alias_impl()
{
// Arrange
var obj = new TestClass_NoMethodB();
var obj = new TestClass_OnlyMethodA();
var shim = obj.Shim<ITestShim_MethodAddAlias>();

// Act
Expand All @@ -472,7 +508,7 @@ public void Added_member_must_not_exist_in_shimmed_type()
public void Added_implementation_must_take_compatible_first_param()
{
// Arrange
var obj = new TestClass_NoMethodB();
var obj = new TestClass_OnlyMethodA();

// Act
Assert.ThrowsException<MissingMemberException>(() =>
Expand Down
32 changes: 16 additions & 16 deletions Shimterface/Internal/ILBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@ private static bool resolveIfInstance(bool isStatic, ILGenerator impl, FieldInfo
}
private static void resolveParameters(ILGenerator impl, MethodBase methodInfo, MethodInfo interfaceMethod, bool isProxy = false)
{
// Pass each parameter from the method call to the implementation
var pars1 = methodInfo.GetParameters();
var pars1 = methodInfo.GetParameters().ToList();
var pars2 = interfaceMethod.GetParameters();
for (var i = 0; i < pars1.Length; ++i)

// Proxies take "this" as first arg
if (isProxy)
{
// Proxies take "this" as first arg
if (isProxy)
{
impl.Emit(OpCodes.Ldarg_0); // this
}
else
{
impl.Emit(OpCodes.Ldarg, i + 1);
impl.EmitTypeUnshim(pars2[i].ParameterType, pars1[i].ParameterType);
}
impl.Emit(OpCodes.Ldarg_0); // this
pars1.RemoveAt(0);
}

// Pass each parameter from the method call to the implementation
for (int i = 0; i < pars1.Count; ++i)
{
impl.Emit(OpCodes.Ldarg, i + 1);
impl.EmitTypeUnshim(pars2[i].ParameterType, pars1[i].ParameterType);
}
}

Expand Down Expand Up @@ -173,10 +173,10 @@ public static void WrapField(this TypeBuilder tb, FieldInfo? instField, ShimBind
tb.MethodThrowException<InvalidOperationException>(binding.InterfaceMethod);
return;
}

impl = tb.DefinePublicMethod(binding.InterfaceMethod);
resolveIfInstance(fieldInfo.IsStatic, impl, instField);

if (args.Length == 0)
{
// Get
Expand Down Expand Up @@ -263,7 +263,7 @@ private static void proxyMethodCall(ILGenerator impl, TypeBuilder tb, FieldInfo?
impl.Emit(OpCodes.Stfld, proxyField);

// Call proxy method
resolveParameters(impl, proxyImplementation, binding.InterfaceMethod, !binding.IsProperty);
resolveParameters(impl, proxyImplementation, binding.InterfaceMethod, !binding.IsProperty || !proxyImplementation.IsSpecialName);
impl.Emit(OpCodes.Call, proxyImplementation);
impl.EmitTypeShim(proxyImplementation.ReturnType, binding.InterfaceMethod.ReturnType);

Expand Down

1 comment on commit 777a608

@IFYates
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes #8

Please sign in to comment.