Skip to content

Commit

Permalink
Fix building proxies for classess with static interface members (#3298)
Browse files Browse the repository at this point in the history
Fixes #3295
  • Loading branch information
hazzik committed May 9, 2023
1 parent ed7a6d8 commit 43c5fce
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
44 changes: 44 additions & 0 deletions src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,50 @@ private static BinaryFormatter GetFormatter()
#endif
}

#if NETCOREAPP3_1_OR_GREATER
public interface IWithStaticMethods
{
// C# 8
static void StaticMethod()
{
}

#if NET7_0_OR_GREATER
// C# 11
static abstract void StaticAbstractMethod();

// C# 11
static virtual void StaticVirtualMethod()
{
}
#endif
}

public class ClassWithStaticInterfaceMethods : IWithStaticMethods
{
public static void StaticAbstractMethod()
{
}
}

[Test(Description = "GH3295")]
public void VerifyProxyForClassWithStaticInterfaceMethod()
{
var factory = new StaticProxyFactory();
factory.PostInstantiate(
typeof(ClassWithStaticInterfaceMethods).FullName,
typeof(ClassWithStaticInterfaceMethods),
new HashSet<System.Type> { typeof(INHibernateProxy) },
null, null, null, true);

var proxy = factory.GetProxy(1, null);
Assert.That(proxy, Is.Not.Null);
Assert.That(proxy, Is.InstanceOf<ClassWithStaticInterfaceMethods>());

Assert.That(factory.GetFieldInterceptionProxy(), Is.InstanceOf<ClassWithStaticInterfaceMethods>());
}
#endif

#if NETFX
private static void VerifyGeneratedAssembly(System.Action assemblyGenerator)
{
Expand Down
11 changes: 5 additions & 6 deletions src/NHibernate/Proxy/ProxyBuilderHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ namespace NHibernate.Proxy
{
internal static class ProxyBuilderHelper
{
private const BindingFlags ProxiableMethodsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

private static readonly ConstructorInfo ObjectConstructor = typeof(object).GetConstructor(System.Type.EmptyTypes);
private static readonly ConstructorInfo SecurityCriticalAttributeConstructor = typeof(SecurityCriticalAttribute).GetConstructor(System.Type.EmptyTypes);
private static readonly ConstructorInfo IgnoresAccessChecksToAttributeConstructor = typeof(IgnoresAccessChecksToAttribute).GetConstructor(new[] {typeof(string)});
Expand Down Expand Up @@ -94,23 +96,20 @@ internal static void CallDefaultBaseConstructor(ILGenerator il, System.Type pare

internal static IEnumerable<MethodInfo> GetProxiableMethods(System.Type type)
{
const BindingFlags candidateMethodsBindingFlags =
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

return type.GetMethods(candidateMethodsBindingFlags).Where(m => m.IsProxiable());
return type.GetMethods(ProxiableMethodsBindingFlags).Where(m => m.IsProxiable());
}

internal static IEnumerable<MethodInfo> GetProxiableMethods(System.Type type, IEnumerable<System.Type> interfaces)
{
if (type.IsInterface || type == typeof(object) || type.GetInterfaces().Length == 0)
{
return GetProxiableMethods(type)
.Concat(interfaces.SelectMany(i => i.GetMethods()))
.Concat(interfaces.SelectMany(i => i.GetMethods(ProxiableMethodsBindingFlags)))
.Distinct();
}

var proxiableMethods = new HashSet<MethodInfo>(GetProxiableMethods(type), new MethodInfoComparer(type));
foreach (var interfaceMethod in interfaces.SelectMany(i => i.GetMethods()))
foreach (var interfaceMethod in interfaces.SelectMany(i => i.GetMethods(ProxiableMethodsBindingFlags)))
{
proxiableMethods.Add(interfaceMethod);
}
Expand Down

0 comments on commit 43c5fce

Please sign in to comment.