Skip to content

Commit

Permalink
#12 Clean up implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Miista committed May 2, 2024
1 parent 447b3ed commit 3ff8edb
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 7 deletions.
48 changes: 48 additions & 0 deletions src/Pose/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Linq;
using System.Reflection;

namespace Pose.Extensions
{
internal static class TypeExtensions
{
public static bool ImplementsInterface<TInterface>(this Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (!typeof(TInterface).IsInterface) throw new InvalidOperationException($"{typeof(TInterface)} is not an interface.");

return type.GetInterfaces().Any(interfaceType => interfaceType == typeof(TInterface));
}

public static bool HasAttribute<TAttribute>(this Type type) where TAttribute : Attribute
{
if (type == null) throw new ArgumentNullException(nameof(type));

var compilerGeneratedAttribute = type.GetCustomAttribute<TAttribute>() ?? type.ReflectedType?.GetCustomAttribute<TAttribute>();

return compilerGeneratedAttribute != null;
}

public static MethodInfo GetExplicitlyImplementedMethod<TInterface>(this Type type, string methodName)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (string.IsNullOrWhiteSpace(methodName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(methodName));

var interfaceType = type.GetInterfaceType<TInterface>() ?? throw new Exception();
var method = interfaceType.GetMethod(methodName) ?? throw new Exception();
var methodDeclaringType = method.DeclaringType ?? throw new Exception($"The {methodName} method does not have a declaring type");
var interfaceMapping = type.GetInterfaceMap(methodDeclaringType);
var requestedTargetMethod = interfaceMapping.TargetMethods.FirstOrDefault(m => m.Name == methodName);

return requestedTargetMethod;
}

private static Type GetInterfaceType<TInterface>(this Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (!typeof(TInterface).IsInterface) throw new InvalidOperationException($"{typeof(TInterface)} is not an interface.");

return type.GetInterfaces().FirstOrDefault(interfaceType => interfaceType == typeof(TInterface));
}
}
}
24 changes: 17 additions & 7 deletions src/Pose/Helpers/StubHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;

using System.Runtime.CompilerServices;
using Pose.Extensions;

namespace Pose.Helpers
Expand Down Expand Up @@ -58,18 +58,28 @@ public static MethodInfo DeVirtualizeMethod(Type thisType, MethodInfo virtualMet

var bindingFlags = BindingFlags.Instance | (virtualMethod.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
var types = virtualMethod.GetParameters().Select(p => p.ParameterType).ToArray();

if (thisType.IsNestedPrivate && thisType.GetInterfaces().Any(i => i.Name == "IAsyncStateMachine"))
{
var nestedType = thisType;
var targetMethod = nestedType.GetInterfaceMap(nestedType.GetInterfaces()[0].GetMethod("MoveNext").DeclaringType).TargetMethods[0];

return targetMethod;
if (IsAsync(thisType))
{
return thisType.GetExplicitlyImplementedMethod<IAsyncStateMachine>(nameof(IAsyncStateMachine.MoveNext));
}

return thisType.GetMethod(virtualMethod.Name, bindingFlags, null, types, null);
}

private static bool IsAsync(Type thisType)
{
return
// State machines are generated by the compiler...
thisType.HasAttribute<CompilerGeneratedAttribute>()

// as nested private classes...
&& thisType.IsNestedPrivate

// which implements IAsyncStateMachine.
&& thisType.ImplementsInterface<IAsyncStateMachine>();
}

public static Module GetOwningModule() => typeof(StubHelper).Module;

public static bool IsIntrinsic(MethodBase method)
Expand Down

0 comments on commit 3ff8edb

Please sign in to comment.