Update DuckTyping types with the latest changes (#1717)

* Change the accessibility for most types in the OpenTelemetry.AutoInstrumentation.DuckTyping namespace, except for DuckType (and inner classes) and IDuckType

* Port the latest dd-trace-dotnet DuckTyping changes into this repo, after removing nullable type references
This commit is contained in:
Zach Montoya 2022-12-07 02:34:41 -08:00 committed by GitHub
parent 339a310e47
commit 90d7bec37e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 2344 additions and 879 deletions

View File

@ -1,4 +1,3 @@
const OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.DefaultFlags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy -> System.Reflection.BindingFlags
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetInvoker
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn.CallTargetReturn() -> void
@ -14,67 +13,19 @@ OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.CallTargetState(Sys
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.CallTargetState(System.Diagnostics.Activity activity, object state, System.DateTimeOffset? startTime) -> void
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.StartTime.get -> System.DateTimeOffset?
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.State.get -> object
OpenTelemetry.AutoInstrumentation.DuckTyping.CreateProxyInstance<T>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.BindingFlags.get -> System.Reflection.BindingFlags
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.BindingFlags.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.DuckAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ExplicitInterfaceTypeName.get -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ExplicitInterfaceTypeName.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.GenericParameterTypeNames.get -> string[]
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.GenericParameterTypeNames.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Kind.get -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Kind.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Name.get -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Name.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ParameterTypeNames.get -> string[]
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ParameterTypeNames.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckCopyAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckCopyAttribute.DuckCopyAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckFieldAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckFieldAttribute.DuckFieldAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIgnoreAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIgnoreAttribute.DuckIgnoreAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIncludeAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIncludeAttribute.DuckIncludeAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind.Field = 1 -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind.Property = 0 -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute.Arguments.get -> string[]
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute.DuckReverseMethodAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute.DuckReverseMethodAttribute(params string[] arguments) -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CanCreate() -> bool
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateInstance<T>(object instance) -> T
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateInstance<T, TOriginal>(TOriginal instance) -> T
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateTypeResult() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.ProxyType.get -> System.Type
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.DelegateCache<TProxyDelegate>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeFieldIsReadonlyException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeInvalidTypeConversionException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyArgumentsLengthException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyCantBeReadException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyCantBeWrittenException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyOrFieldNotFoundException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyAndTargetMethodParameterSignatureMismatchException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyMethodParameterIsMissingException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyTypeDefinitionIsNull
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeStructMembersCannotBeChangedException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTargetMethodAmbiguousMatchException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTargetMethodNotFoundException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTargetObjectInstanceIsNull
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTypeIsNotPublicException
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.ToString() -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Type.get -> System.Type
OpenTelemetry.AutoInstrumentation.DuckTyping.IgnoresAccessChecksToAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.IgnoresAccessChecksToAttribute.AssemblyName.get -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.IgnoresAccessChecksToAttribute.IgnoresAccessChecksToAttribute(string assemblyName) -> void
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.Column -> int
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.ErrorLocationStruct() -> void
@ -138,24 +89,20 @@ static OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn<T>.GetDefau
static OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.GetDefault() -> OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CanCreate(System.Type proxyType, object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CanCreate<T>(object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.Create(System.Type proxyType, object instance) -> OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.Create(System.Type proxyType, object instance) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.Create<T>(object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateReverse(System.Type typeToDeriveFrom, object delegationInstance) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetOrCreateReverseProxyType(System.Type typeToDeriveFrom, System.Type delegationType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.CanCreate(object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.Create(object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.CreateFrom<TOriginal>(TOriginal instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.CreateReverse(object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.GetReverseProxy(System.Type targetType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.GetProxy(System.Type targetType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.DelegateCache<TProxyDelegate>.GetDelegate() -> TProxyDelegate
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetOrCreateProxyType(System.Type proxyType, System.Type targetType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckAs(this object instance, System.Type targetType) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckAs<T>(this object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckCast(this object instance, System.Type targetType) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckCast<T>(this object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckIs(this object instance, System.Type targetType) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckIs<T>(this object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.TryDuckCast(this object instance, System.Type targetType, out object value) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.TryDuckCast<T>(this object instance, out T value) -> bool
static OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration.OnAsyncMethodEnd<TTarget, TExecutionResult>(TTarget instance, TExecutionResult executionResult, System.Exception exception, OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState state) -> TExecutionResult
static OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration.OnMethodBegin<TTarget, TContext>(TTarget instance, TContext context) -> OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.IsVisible -> bool
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.Type -> System.Type
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo -> System.Reflection.MethodInfo
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo -> System.Reflection.MethodInfo
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo.get -> System.Reflection.MethodInfo
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo.get -> System.Reflection.MethodInfo

View File

@ -1,4 +1,3 @@
const OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.DefaultFlags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy -> System.Reflection.BindingFlags
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetInvoker
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn.CallTargetReturn() -> void
@ -14,67 +13,19 @@ OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.CallTargetState(Sys
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.CallTargetState(System.Diagnostics.Activity activity, object state, System.DateTimeOffset? startTime) -> void
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.StartTime.get -> System.DateTimeOffset?
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.State.get -> object
OpenTelemetry.AutoInstrumentation.DuckTyping.CreateProxyInstance<T>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.BindingFlags.get -> System.Reflection.BindingFlags
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.BindingFlags.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.DuckAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ExplicitInterfaceTypeName.get -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ExplicitInterfaceTypeName.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.GenericParameterTypeNames.get -> string[]
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.GenericParameterTypeNames.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Kind.get -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Kind.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Name.get -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.Name.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ParameterTypeNames.get -> string[]
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckAttribute.ParameterTypeNames.set -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckCopyAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckCopyAttribute.DuckCopyAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckFieldAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckFieldAttribute.DuckFieldAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIgnoreAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIgnoreAttribute.DuckIgnoreAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIncludeAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckIncludeAttribute.DuckIncludeAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind.Field = 1 -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind.Property = 0 -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckKind
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute.Arguments.get -> string[]
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute.DuckReverseMethodAttribute() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckReverseMethodAttribute.DuckReverseMethodAttribute(params string[] arguments) -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CanCreate() -> bool
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateInstance<T>(object instance) -> T
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateInstance<T, TOriginal>(TOriginal instance) -> T
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateTypeResult() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.ProxyType.get -> System.Type
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.DelegateCache<TProxyDelegate>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeFieldIsReadonlyException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeInvalidTypeConversionException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyArgumentsLengthException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyCantBeReadException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyCantBeWrittenException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypePropertyOrFieldNotFoundException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyAndTargetMethodParameterSignatureMismatchException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyMethodParameterIsMissingException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeProxyTypeDefinitionIsNull
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeStructMembersCannotBeChangedException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTargetMethodAmbiguousMatchException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTargetMethodNotFoundException
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTargetObjectInstanceIsNull
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeTypeIsNotPublicException
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.ToString() -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Type.get -> System.Type
OpenTelemetry.AutoInstrumentation.DuckTyping.IgnoresAccessChecksToAttribute
OpenTelemetry.AutoInstrumentation.DuckTyping.IgnoresAccessChecksToAttribute.AssemblyName.get -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.IgnoresAccessChecksToAttribute.IgnoresAccessChecksToAttribute(string assemblyName) -> void
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.Column -> int
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.ErrorLocationStruct() -> void
@ -138,24 +89,20 @@ static OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn<T>.GetDefau
static OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.GetDefault() -> OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CanCreate(System.Type proxyType, object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CanCreate<T>(object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.Create(System.Type proxyType, object instance) -> OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.Create(System.Type proxyType, object instance) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.Create<T>(object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateReverse(System.Type typeToDeriveFrom, object delegationInstance) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetOrCreateReverseProxyType(System.Type typeToDeriveFrom, System.Type delegationType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.CanCreate(object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.Create(object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.CreateFrom<TOriginal>(TOriginal instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.CreateReverse(object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.GetReverseProxy(System.Type targetType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.GetProxy(System.Type targetType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.DelegateCache<TProxyDelegate>.GetDelegate() -> TProxyDelegate
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetOrCreateProxyType(System.Type proxyType, System.Type targetType) -> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckAs(this object instance, System.Type targetType) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckAs<T>(this object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckCast(this object instance, System.Type targetType) -> object
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckCast<T>(this object instance) -> T
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckIs(this object instance, System.Type targetType) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.DuckIs<T>(this object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.TryDuckCast(this object instance, System.Type targetType, out object value) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckTypeExtensions.TryDuckCast<T>(this object instance, out T value) -> bool
static OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration.OnAsyncMethodEnd<TTarget, TExecutionResult>(TTarget instance, TExecutionResult executionResult, System.Exception exception, OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState state) -> TExecutionResult
static OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ExecuteAsyncIntegration.OnMethodBegin<TTarget, TContext>(TTarget instance, TContext context) -> OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.IsVisible -> bool
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.Type -> System.Type
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo -> System.Reflection.MethodInfo
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo -> System.Reflection.MethodInfo
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo.get -> System.Reflection.MethodInfo
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo.get -> System.Reflection.MethodInfo

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using System;
using System.Reflection;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
@ -22,7 +21,7 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Duck kind
/// </summary>
public enum DuckKind
internal enum DuckKind
{
/// <summary>
/// Property
@ -38,41 +37,15 @@ public enum DuckKind
/// <summary>
/// Duck attribute
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field, AllowMultiple = false)]
public class DuckAttribute : Attribute
internal class DuckAttribute : DuckAttributeBase
{
/// <summary>
/// Default BindingFlags
/// </summary>
public const BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
/// <summary>
/// Gets or sets the underlying type member name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets duck kind
/// </summary>
public DuckKind Kind { get; set; } = DuckKind.Property;
/// <summary>
/// Gets or sets the binding flags
/// </summary>
public BindingFlags BindingFlags { get; set; } = DefaultFlags;
/// <summary>
/// Gets or sets the generic parameter type names definition for a generic method call (required when calling generic methods and instance type is non public)
/// </summary>
public string[] GenericParameterTypeNames { get; set; }
/// <summary>
/// Gets or sets the parameter type names of the target method (optional / used to disambiguation)
/// </summary>
public string[] ParameterTypeNames { get; set; }
/// <summary>
/// Gets or sets the explicit interface type name
/// </summary>
public string ExplicitInterfaceTypeName { get; set; }
}

View File

@ -0,0 +1,52 @@
// <copyright file="DuckAttributeBase.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System;
using System.Reflection;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Duck attribute
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field, AllowMultiple = false)]
internal abstract class DuckAttributeBase : Attribute
{
/// <summary>
/// Gets or sets the underlying type member name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the binding flags
/// </summary>
public BindingFlags BindingFlags { get; set; } = DuckAttribute.DefaultFlags;
/// <summary>
/// Gets or sets the generic parameter type names definition for a generic method call (required when calling generic methods and instance type is non public)
/// </summary>
public string[] GenericParameterTypeNames { get; set; }
/// <summary>
/// Gets or sets the parameter type names of the target method (optional / used to disambiguation)
/// </summary>
public string[] ParameterTypeNames { get; set; }
/// <summary>
/// Gets or sets the explicit interface type name
/// </summary>
public string ExplicitInterfaceTypeName { get; set; }
}

View File

@ -22,6 +22,6 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// Duck copy struct attribute
/// </summary>
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
public class DuckCopyAttribute : Attribute
internal class DuckCopyAttribute : Attribute
{
}

View File

@ -19,7 +19,7 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Duck attribute where the underlying member is a field
/// </summary>
public class DuckFieldAttribute : DuckAttribute
internal class DuckFieldAttribute : DuckAttribute
{
/// <summary>
/// Initializes a new instance of the <see cref="DuckFieldAttribute"/> class.

View File

@ -22,6 +22,6 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// Ignores the member when DuckTyping
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field, AllowMultiple = false)]
public class DuckIgnoreAttribute : Attribute
internal class DuckIgnoreAttribute : Attribute
{
}

View File

@ -22,6 +22,6 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// Use to include a member that would normally be ignored
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class DuckIncludeAttribute : Attribute
internal class DuckIncludeAttribute : Attribute
{
}

View File

@ -14,34 +14,11 @@
// limitations under the License.
// </copyright>
using System;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Duck reverse method attribute
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class DuckReverseMethodAttribute : Attribute
internal class DuckReverseMethodAttribute : DuckAttributeBase
{
/// <summary>
/// Initializes a new instance of the <see cref="DuckReverseMethodAttribute"/> class.
/// </summary>
public DuckReverseMethodAttribute()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DuckReverseMethodAttribute"/> class.
/// </summary>
/// <param name="arguments">Methods arguments</param>
public DuckReverseMethodAttribute(params string[] arguments)
{
Arguments = arguments;
}
/// <summary>
/// Gets the methods arguments
/// </summary>
public string[] Arguments { get; private set; }
}

View File

@ -25,25 +25,33 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// </summary>
public static partial class DuckType
{
private static MethodBuilder GetFieldGetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, FieldInfo targetField, FieldInfo instanceField)
private static MethodBuilder GetFieldGetMethod(
TypeBuilder proxyTypeBuilder,
Type targetType,
MemberInfo proxyMember,
FieldInfo targetField,
FieldInfo instanceField)
{
string proxyMemberName = proxyMember.Name;
Type proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType : proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object);
MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod(
MethodBuilder proxyMethod = proxyTypeBuilder?.DefineMethod(
"get_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
proxyMemberReturnType,
Type.EmptyTypes);
LazyILGenerator il = new LazyILGenerator(proxyMethod.GetILGenerator());
LazyILGenerator il = new LazyILGenerator(proxyMethod?.GetILGenerator());
Type returnType = targetField.FieldType;
// Load the instance
if (!targetField.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
if (instanceField is not null)
{
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
}
}
// Load the field value to the stack
@ -52,7 +60,7 @@ public static partial class DuckType
// In case is public is pretty simple
il.Emit(targetField.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, targetField);
}
else
else if (targetField.DeclaringType is not null && proxyTypeBuilder is not null)
{
// If the instance or the field are non public we need to create a Dynamic method to overpass the visibility checks
// we can't access non public types so we have to cast to object type (in the instance object and the return type if is needed).
@ -85,20 +93,22 @@ public static partial class DuckType
// Emit the call to the dynamic method
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder);
}
else
{
// Dry run: We enable all checks done in the preview if branch
returnType = UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) ? targetField.FieldType : typeof(object);
ILHelpersExtensions.CheckTypeConversion(targetField.FieldType, returnType);
}
// Check if the type can be converted or if we need to enable duck chaining
if (NeedsDuckChaining(targetField.FieldType, proxyMemberReturnType))
{
if (UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) && targetField.FieldType.IsValueType)
{
il.Emit(OpCodes.Box, targetField.FieldType);
}
UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType);
// WARNING: If targetField.FieldType cannot be duck cast to proxyMemberReturnType
// this will throw an exception at runtime when accessing the member
// We call DuckType.CreateCache<>.Create()
MethodInfo getProxyMethodInfo = typeof(CreateCache<>)
.MakeGenericType(proxyMemberReturnType).GetMethod("Create");
il.Emit(OpCodes.Call, getProxyMethodInfo);
MethodIlHelper.AddIlToDuckChain(il, proxyMemberReturnType, targetField.FieldType);
}
else if (returnType != proxyMemberReturnType)
{
@ -108,29 +118,41 @@ public static partial class DuckType
il.Emit(OpCodes.Ret);
il.Flush();
_methodBuilderGetToken.Invoke(proxyMethod, null);
if (proxyMethod is not null)
{
MethodBuilderGetToken.Invoke(proxyMethod, null);
}
return proxyMethod;
}
private static MethodBuilder GetFieldSetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, FieldInfo targetField, FieldInfo instanceField)
private static MethodBuilder GetFieldSetMethod(
TypeBuilder proxyTypeBuilder,
Type targetType,
MemberInfo proxyMember,
FieldInfo targetField,
FieldInfo instanceField)
{
string proxyMemberName = proxyMember.Name;
Type proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType : proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object);
MethodBuilder method = proxyTypeBuilder.DefineMethod(
MethodBuilder method = proxyTypeBuilder?.DefineMethod(
"set_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
typeof(void),
new[] { proxyMemberReturnType });
LazyILGenerator il = new LazyILGenerator(method.GetILGenerator());
LazyILGenerator il = new LazyILGenerator(method?.GetILGenerator());
Type currentValueType = proxyMemberReturnType;
// Load instance
if (!targetField.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
if (instanceField is not null)
{
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
}
}
// Check if the type can be converted of if we need to enable duck chaining
@ -141,7 +163,7 @@ public static partial class DuckType
il.WriteTypeConversion(proxyMemberReturnType, typeof(IDuckType));
// Call IDuckType.Instance property to get the actual value
il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod, null);
il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod!, null!);
currentValueType = typeof(object);
}
@ -159,10 +181,9 @@ public static partial class DuckType
il.Emit(targetField.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, targetField);
}
else
else if (targetField.DeclaringType is not null && proxyTypeBuilder is not null)
{
// If the instance or the field are non public we need to create a Dynamic method to overpass the visibility checks
string dynMethodName = $"_setField_{targetField.DeclaringType.Name}_{targetField.Name}";
// Convert the field type for the dynamic method
@ -200,10 +221,21 @@ public static partial class DuckType
// Emit the call to the dynamic method
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder);
}
else
{
// Dry run: We enable all checks done in the preview if branch
Type dynValueType = UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) ? targetField.FieldType : typeof(object);
ILHelpersExtensions.CheckTypeConversion(currentValueType, dynValueType);
ILHelpersExtensions.CheckTypeConversion(dynValueType, targetField.FieldType);
}
il.Emit(OpCodes.Ret);
il.Flush();
_methodBuilderGetToken.Invoke(method, null);
if (method is not null)
{
MethodBuilderGetToken.Invoke(method, null);
}
return method;
}
}

View File

@ -27,8 +27,21 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// </summary>
public static partial class DuckType
{
private static MethodBuilder GetPropertyGetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, PropertyInfo targetProperty, FieldInfo instanceField)
private static MethodBuilder GetPropertyGetMethod(
TypeBuilder proxyTypeBuilder,
Type targetType,
MemberInfo proxyMember,
PropertyInfo targetProperty,
FieldInfo instanceField,
Func<LazyILGenerator, Type, Type, Type> duckCastInnerToOuterFunc,
Func<Type, Type, bool> needsDuckChaining)
{
MethodInfo targetMethod = targetProperty.GetMethod;
if (targetMethod is null)
{
return null;
}
string proxyMemberName = proxyMember.Name;
Type proxyMemberReturnType = typeof(object);
Type[] proxyParameterTypes = Type.EmptyTypes;
@ -53,21 +66,23 @@ public static partial class DuckType
}
}
MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod(
MethodBuilder proxyMethod = proxyTypeBuilder?.DefineMethod(
"get_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
proxyMemberReturnType,
proxyParameterTypes);
LazyILGenerator il = new LazyILGenerator(proxyMethod.GetILGenerator());
MethodInfo targetMethod = targetProperty.GetMethod;
LazyILGenerator il = new LazyILGenerator(proxyMethod?.GetILGenerator());
Type returnType = targetProperty.PropertyType;
// Load the instance if needed
if (!targetMethod.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
if (instanceField is not null)
{
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
}
}
// Load the indexer keys to the stack
@ -84,7 +99,7 @@ public static partial class DuckType
il.Emit(OpCodes.Castclass, typeof(IDuckType));
// Call IDuckType.Instance property to get the actual value
il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod, null);
il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod!, null!);
targetParamType = typeof(object);
}
else
@ -108,7 +123,7 @@ public static partial class DuckType
if (targetMethod.IsPublic)
{
// We can emit a normal call if we have a public instance with a public property method.
il.EmitCall(targetMethod.IsStatic || instanceField.FieldType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null);
il.EmitCall(targetMethod.IsStatic || (instanceField?.FieldType.IsValueType ?? false) ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null!);
}
else
{
@ -116,7 +131,7 @@ public static partial class DuckType
il.WriteMethodCalli(targetMethod);
}
}
else
else if (targetProperty.DeclaringType is not null && proxyTypeBuilder is not null && instanceField is not null)
{
// If the instance is not public we need to create a Dynamic method to overpass the visibility checks
// we can't access non public types so we have to cast to object type (in the instance object and the return type).
@ -143,7 +158,7 @@ public static partial class DuckType
dynIL.WriteTypeConversion(dynParameters[idx], targetParameters[idx]);
}
dynIL.EmitCall(targetMethod.IsStatic || instanceField.FieldType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null);
dynIL.EmitCall(targetMethod.IsStatic || instanceField.FieldType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null!);
dynIL.WriteTypeConversion(targetProperty.PropertyType, returnType);
dynIL.Emit(OpCodes.Ret);
dynIL.Flush();
@ -151,21 +166,29 @@ public static partial class DuckType
// Emit the call to the dynamic method
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder);
}
else
{
// Dry run: We enable all checks done in the preview if branch
returnType = UseDirectAccessTo(proxyTypeBuilder, targetProperty.PropertyType) ? targetProperty.PropertyType : typeof(object);
Type[] targetParameters = GetPropertyGetParametersTypes(proxyTypeBuilder, targetProperty, false, !targetMethod.IsStatic).ToArray();
Type[] dynParameters = targetMethod.IsStatic ? targetParametersTypes : (new[] { typeof(object) }).Concat(targetParametersTypes).ToArray();
for (int idx = targetMethod.IsStatic ? 0 : 1; idx < dynParameters.Length; idx++)
{
ILHelpersExtensions.CheckTypeConversion(dynParameters[idx], targetParameters[idx]);
}
ILHelpersExtensions.CheckTypeConversion(targetProperty.PropertyType, returnType);
}
// Handle the return value
// Check if the type can be converted or if we need to enable duck chaining
if (NeedsDuckChaining(targetProperty.PropertyType, proxyMemberReturnType))
if (needsDuckChaining(targetProperty.PropertyType, proxyMemberReturnType))
{
if (UseDirectAccessTo(proxyTypeBuilder, targetProperty.PropertyType) && targetProperty.PropertyType.IsValueType)
{
il.Emit(OpCodes.Box, targetProperty.PropertyType);
}
UseDirectAccessTo(proxyTypeBuilder, targetProperty.PropertyType);
// We call DuckType.CreateCache<>.Create()
MethodInfo getProxyMethodInfo = typeof(CreateCache<>)
.MakeGenericType(proxyMemberReturnType).GetMethod("Create");
il.Emit(OpCodes.Call, getProxyMethodInfo);
// If this is a forward duck type, we need to create a duck type from the original instance
// If this is a reverse duck type, we need to cast to IDuckType and extract the original instance
duckCastInnerToOuterFunc(il, proxyMemberReturnType, targetProperty.PropertyType);
}
else if (returnType != proxyMemberReturnType)
{
@ -175,12 +198,29 @@ public static partial class DuckType
il.Emit(OpCodes.Ret);
il.Flush();
_methodBuilderGetToken.Invoke(proxyMethod, null);
if (proxyMethod is not null)
{
MethodBuilderGetToken.Invoke(proxyMethod, null);
}
return proxyMethod;
}
private static MethodBuilder GetPropertySetMethod(TypeBuilder proxyTypeBuilder, Type targetType, MemberInfo proxyMember, PropertyInfo targetProperty, FieldInfo instanceField)
private static MethodBuilder GetPropertySetMethod(
TypeBuilder proxyTypeBuilder,
Type targetType,
MemberInfo proxyMember,
PropertyInfo targetProperty,
FieldInfo instanceField,
Func<LazyILGenerator, Type, Type, Type> duckCastOuterToInner,
Func<Type, Type, bool> needsDuckChaining)
{
MethodInfo targetMethod = targetProperty.SetMethod;
if (targetMethod is null)
{
return null;
}
string proxyMemberName = null;
Type[] proxyParameterTypes = Type.EmptyTypes;
Type[] targetParametersTypes = GetPropertySetParametersTypes(proxyTypeBuilder, targetProperty, true).ToArray();
@ -197,27 +237,29 @@ public static partial class DuckType
else if (proxyMember is FieldInfo proxyField)
{
proxyMemberName = proxyField.Name;
proxyParameterTypes = new Type[] { proxyField.FieldType };
proxyParameterTypes = new[] { proxyField.FieldType };
if (proxyParameterTypes.Length != targetParametersTypes.Length)
{
DuckTypePropertyArgumentsLengthException.Throw(targetProperty);
}
}
MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod(
MethodBuilder proxyMethod = proxyTypeBuilder?.DefineMethod(
"set_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
typeof(void),
proxyParameterTypes);
LazyILGenerator il = new LazyILGenerator(proxyMethod.GetILGenerator());
MethodInfo targetMethod = targetProperty.SetMethod;
LazyILGenerator il = new LazyILGenerator(proxyMethod?.GetILGenerator());
// Load the instance if needed
if (!targetMethod.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
if (instanceField is not null)
{
il.Emit(instanceField.FieldType.IsValueType ? OpCodes.Ldflda : OpCodes.Ldfld, instanceField);
}
}
// Load the indexer keys and set value to the stack
@ -227,16 +269,15 @@ public static partial class DuckType
Type targetParamType = targetParametersTypes[pIndex];
// Check if the type can be converted of if we need to enable duck chaining
if (NeedsDuckChaining(targetParamType, proxyParamType))
if (needsDuckChaining(targetParamType, proxyParamType))
{
// Load the argument and cast it as Duck type
il.WriteLoadArgument(pIndex, false);
il.Emit(OpCodes.Castclass, typeof(IDuckType));
// Call IDuckType.Instance property to get the actual value
il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod, null);
targetParamType = typeof(object);
// If this is a forward duck type, we need to cast to IDuckType and extract the original instance
// and set the targetParamType to object
// If this is a reverse duck type, we need to create a duck type from the original instance
targetParamType = duckCastOuterToInner(il, targetParamType, proxyParamType);
}
else
{
@ -258,7 +299,7 @@ public static partial class DuckType
if (targetMethod.IsPublic)
{
// We can emit a normal call if we have a public instance with a public property method.
il.EmitCall(targetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null);
il.EmitCall(targetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null!);
}
else
{
@ -266,7 +307,7 @@ public static partial class DuckType
il.WriteMethodCalli(targetMethod);
}
}
else
else if (targetProperty.DeclaringType is not null && proxyTypeBuilder is not null && instanceField is not null)
{
// If the instance is not public we need to create a Dynamic method to overpass the visibility checks
// we can't access non public types so we have to cast to object type (in the instance object and the return type).
@ -292,17 +333,30 @@ public static partial class DuckType
dynIL.WriteTypeConversion(dynParameters[idx], targetParameters[idx]);
}
dynIL.EmitCall(targetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null);
dynIL.EmitCall(targetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, targetMethod, null!);
dynIL.Emit(OpCodes.Ret);
dynIL.Flush();
// Create and load delegate for the DynamicMethod
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder);
}
else
{
Type[] targetParameters = GetPropertySetParametersTypes(proxyTypeBuilder, targetProperty, false, !targetMethod.IsStatic).ToArray();
Type[] dynParameters = targetMethod.IsStatic ? targetParametersTypes : (new[] { typeof(object) }).Concat(targetParametersTypes).ToArray();
for (int idx = targetMethod.IsStatic ? 0 : 1; idx < dynParameters.Length; idx++)
{
ILHelpersExtensions.CheckTypeConversion(dynParameters[idx], targetParameters[idx]);
}
}
il.Emit(OpCodes.Ret);
il.Flush();
_methodBuilderGetToken.Invoke(proxyMethod, null);
if (proxyMethod is not null)
{
MethodBuilderGetToken.Invoke(proxyMethod, null);
}
return proxyMethod;
}

View File

@ -20,6 +20,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
@ -28,43 +30,123 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// </summary>
public static partial class DuckType
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly object Locker;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly ConcurrentDictionary<TypesTuple, Lazy<CreateTypeResult>> DuckTypeCache;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly Dictionary<Assembly, ModuleBuilder> ActiveBuilders;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly Dictionary<ModuleBuilder, HashSet<string>> IgnoresAccessChecksToAssembliesSetDictionary;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly MethodInfo _getTypeFromHandleMethodInfo;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly MethodInfo _enumToObjectMethodInfo;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly PropertyInfo _duckTypeInstancePropertyInfo;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly MethodInfo _methodBuilderGetToken;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly ConstructorInfo _ignoresAccessChecksToAttributeCtor;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static long _assemblyCount;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static long _typeCount;
static DuckType()
{
Locker = new();
DuckTypeCache = new();
ActiveBuilders = new();
IgnoresAccessChecksToAssembliesSetDictionary = new();
_getTypeFromHandleMethodInfo = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle));
_enumToObjectMethodInfo = typeof(Enum).GetMethod(nameof(Enum.ToObject), new[] { typeof(Type), typeof(object) });
_duckTypeInstancePropertyInfo = typeof(IDuckType).GetProperty(nameof(IDuckType.Instance));
_methodBuilderGetToken = typeof(MethodBuilder).GetMethod("GetToken", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
_ignoresAccessChecksToAttributeCtor = typeof(IgnoresAccessChecksToAttribute).GetConstructor(new[] { typeof(string) });
_assemblyCount = 0;
_typeCount = 0;
}
/// <summary>
/// Gets the Type.GetTypeFromHandle method info
/// </summary>
public static readonly MethodInfo GetTypeFromHandleMethodInfo = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle));
public static MethodInfo GetTypeFromHandleMethodInfo
{
get
{
if (_getTypeFromHandleMethodInfo is null)
{
DuckTypeException.Throw($"{nameof(Type)}.{nameof(Type.GetTypeFromHandle)}() cannot be found.");
}
return _getTypeFromHandleMethodInfo;
}
}
/// <summary>
/// Gets the Enum.ToObject method info
/// </summary>
public static readonly MethodInfo EnumToObjectMethodInfo = typeof(Enum).GetMethod(nameof(Enum.ToObject), new[] { typeof(Type), typeof(object) });
public static MethodInfo EnumToObjectMethodInfo
{
get
{
if (_enumToObjectMethodInfo is null)
{
DuckTypeException.Throw($"{nameof(Enum)}.{nameof(Enum.ToObject)}() cannot be found.");
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly object _locker = new object();
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly ConcurrentDictionary<TypesTuple, Lazy<CreateTypeResult>> DuckTypeCache = new ConcurrentDictionary<TypesTuple, Lazy<CreateTypeResult>>();
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly PropertyInfo DuckTypeInstancePropertyInfo = typeof(IDuckType).GetProperty(nameof(IDuckType.Instance));
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly MethodInfo _methodBuilderGetToken = typeof(MethodBuilder).GetMethod("GetToken", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly Dictionary<Assembly, ModuleBuilder> ActiveBuilders = new Dictionary<Assembly, ModuleBuilder>();
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static long _assemblyCount = 0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static long _typeCount = 0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static ConstructorInfo _ignoresAccessChecksToAttributeCtor = typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) });
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static Dictionary<ModuleBuilder, HashSet<string>> _ignoresAccessChecksToAssembliesSetDictionary = new Dictionary<ModuleBuilder, HashSet<string>>();
return _enumToObjectMethodInfo;
}
}
internal static long AssemblyCount => _assemblyCount;
internal static long TypeCount => _typeCount;
private static PropertyInfo DuckTypeInstancePropertyInfo
{
get
{
if (_duckTypeInstancePropertyInfo is null)
{
DuckTypeException.Throw($"{nameof(IDuckType)}.{nameof(IDuckType.Instance)} cannot be found.");
}
return _duckTypeInstancePropertyInfo;
}
}
private static MethodInfo MethodBuilderGetToken
{
get
{
if (_methodBuilderGetToken is null)
{
DuckTypeException.Throw($"{nameof(MethodBuilder)}.GetToken() cannot be found.");
}
return _methodBuilderGetToken;
}
}
private static ConstructorInfo IgnoresAccessChecksToAttributeCtor
{
get
{
if (_ignoresAccessChecksToAttributeCtor is null)
{
DuckTypeException.Throw($"{nameof(IgnoresAccessChecksToAttribute)}.ctor() cannot be found.");
}
return _ignoresAccessChecksToAttributeCtor;
}
}
/// <summary>
/// Gets the ModuleBuilder instance from a target type. (.NET Framework / Non AssemblyLoadContext version)
/// </summary>
@ -73,14 +155,14 @@ public static partial class DuckType
/// <returns>ModuleBuilder instance</returns>
private static ModuleBuilder GetModuleBuilder(Type targetType, bool isVisible)
{
Assembly targetAssembly = targetType.Assembly ?? typeof(DuckType).Assembly;
Assembly targetAssembly = targetType.Assembly;
if (!isVisible)
{
// If the target type is not visible then we create a new module builder.
// This is the only way to IgnoresAccessChecksToAttribute to work.
// We can't reuse the module builder if the attributes collection changes.
return CreateModuleBuilder($"DuckTypeNotVisibleAssembly.{targetType.Name}", targetAssembly);
return CreateModuleBuilder(DuckTypeConstants.DuckTypeNotVisibleAssemblyPrefix + targetType.Name, targetAssembly);
}
if (targetType.IsGenericType)
@ -89,14 +171,14 @@ public static partial class DuckType
{
if (type.Assembly != targetAssembly)
{
return CreateModuleBuilder($"DuckTypeGenericTypeAssembly.{targetType.Name}", targetAssembly);
return CreateModuleBuilder(DuckTypeConstants.DuckTypeGenericTypeAssemblyPrefix + targetType.Name, targetAssembly);
}
}
}
if (!ActiveBuilders.TryGetValue(targetAssembly, out var moduleBuilder))
{
moduleBuilder = CreateModuleBuilder($"DuckTypeAssembly.{targetType.Assembly?.GetName().Name}", targetAssembly);
moduleBuilder = CreateModuleBuilder(DuckTypeConstants.DuckTypeAssemblyPrefix + targetType.Assembly.GetName().Name, targetAssembly);
ActiveBuilders.Add(targetAssembly, moduleBuilder);
}
@ -126,6 +208,11 @@ public static partial class DuckType
/// <returns>TProxyDelegate instance</returns>
public static TProxyDelegate GetDelegate()
{
if (_delegate is null)
{
DuckTypeException.Throw("Delegate instance in DelegateCache is null, please ensure that FillDelegate is called before this call.");
}
return _delegate;
}

View File

@ -52,7 +52,7 @@ public static partial class DuckType
/// <param name="type">Type to gain internals visibility</param>
private static void EnsureTypeVisibility(ModuleBuilder builder, Type type)
{
EnsureAssemblyNameVisibility(builder, type.Assembly.GetName().Name);
EnsureAssemblyNameVisibility(builder, type.Assembly.GetName().Name ?? string.Empty);
if (type.IsGenericType && !type.IsGenericTypeDefinition)
{
@ -60,7 +60,7 @@ public static partial class DuckType
{
if (!t.IsVisible)
{
EnsureAssemblyNameVisibility(builder, t.Assembly.GetName().Name);
EnsureAssemblyNameVisibility(builder, t.Assembly.GetName().Name ?? string.Empty);
}
}
}
@ -69,26 +69,33 @@ public static partial class DuckType
{
if (!type.IsNestedPublic)
{
EnsureAssemblyNameVisibility(builder, type.Assembly.GetName().Name);
EnsureAssemblyNameVisibility(builder, type.Assembly.GetName().Name ?? string.Empty);
}
// this should be null for non-nested types.
type = type.DeclaringType;
if (type.DeclaringType is { } declaringType)
{
type = declaringType;
}
else
{
break;
}
}
static void EnsureAssemblyNameVisibility(ModuleBuilder builder, string assemblyName)
{
lock (_ignoresAccessChecksToAssembliesSetDictionary)
lock (IgnoresAccessChecksToAssembliesSetDictionary)
{
if (!_ignoresAccessChecksToAssembliesSetDictionary.TryGetValue(builder, out var hashSet))
if (!IgnoresAccessChecksToAssembliesSetDictionary.TryGetValue(builder, out var hashSet))
{
hashSet = new HashSet<string>();
_ignoresAccessChecksToAssembliesSetDictionary[builder] = hashSet;
IgnoresAccessChecksToAssembliesSetDictionary[builder] = hashSet;
}
if (hashSet.Add(assemblyName))
{
((AssemblyBuilder)builder.Assembly).SetCustomAttribute(new CustomAttributeBuilder(_ignoresAccessChecksToAttributeCtor, new object[] { assemblyName }));
((AssemblyBuilder)builder.Assembly).SetCustomAttribute(new CustomAttributeBuilder(IgnoresAccessChecksToAttributeCtor, new object[] { assemblyName }));
}
}
}
@ -98,10 +105,10 @@ public static partial class DuckType
{
// The condition to apply duck chaining is:
// 1. Is a struct with the DuckCopy attribute
// 2. Both types must be differents.
// 2. Both types must be different.
// 3. The proxy type (duck chaining proxy definition type) can't be a struct
// 4. The proxy type can't be a generic parameter (should be a well known type)
// 5. Can't be a base type or an iterface implemented by the targetType type.
// 5. Can't be a base type or an interface implemented by the targetType type.
// 6. The proxy type can't be a CLR type
return proxyType.GetCustomAttribute<DuckCopyAttribute>() != null ||
(proxyType != targetType &&
@ -112,14 +119,14 @@ public static partial class DuckType
}
/// <summary>
/// Gets if the direct access method should be used or the inderect method (dynamic method)
/// Gets if the direct access method should be used or the indirect method (dynamic method)
/// </summary>
/// <param name="builder">Module builder</param>
/// <param name="targetType">Target type</param>
/// <returns>true for direct method; otherwise, false.</returns>
private static bool UseDirectAccessTo(ModuleBuilder builder, Type targetType)
{
if (builder == null)
if (builder is null)
{
return targetType.IsPublic || targetType.IsNestedPublic;
}
@ -129,23 +136,18 @@ public static partial class DuckType
}
/// <summary>
/// Gets if the direct access method should be used or the inderect method (dynamic method)
/// Gets if the direct access method should be used or the indirect method (dynamic method)
/// </summary>
/// <param name="builder">Type builder</param>
/// <param name="targetType">Target type</param>
/// <returns>true for direct method; otherwise, false.</returns>
private static bool UseDirectAccessTo(TypeBuilder builder, Type targetType)
{
return UseDirectAccessTo((ModuleBuilder)builder?.Module, targetType);
}
if (builder is null)
{
return true;
}
/// <summary>
/// Gets if the direct access method should be used or the inderect method (dynamic method)
/// </summary>
/// <param name="targetType">Target type</param>
/// <returns>true for direct method; otherwise, false.</returns>
private static bool UseDirectAccessTo(Type targetType)
{
return UseDirectAccessTo((ModuleBuilder)null, targetType);
return UseDirectAccessTo((ModuleBuilder)builder.Module, targetType);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
// <copyright file="DuckTypeConstants.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
internal static class DuckTypeConstants
{
internal const string DuckTypeAssemblyPrefix = "DuckTypeAssembly.";
internal const string DuckTypeNotVisibleAssemblyPrefix = "DuckTypeNotVisibleAssembly.";
internal const string DuckTypeGenericTypeAssemblyPrefix = "DuckTypeGenericTypeAssembly.";
}

View File

@ -15,9 +15,11 @@
// </copyright>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
#pragma warning disable SA1649 // File name must match first type name
#pragma warning disable SA1402 // File may only contain a single class
@ -26,18 +28,37 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// DuckType Exception
/// </summary>
public class DuckTypeException : Exception
internal class DuckTypeException : Exception
{
internal DuckTypeException(string message)
protected DuckTypeException(string message)
: base(message)
{
}
protected DuckTypeException(string message, Exception innerException)
: base(message, innerException)
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(string message)
{
throw new DuckTypeException(message);
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(string message, Exception innerException)
{
throw new DuckTypeException(message, innerException);
}
}
/// <summary>
/// DuckType proxy type definition is null
/// </summary>
public class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
internal class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
{
private DuckTypeProxyTypeDefinitionIsNull()
: base($"The proxy type definition is null.")
@ -45,6 +66,7 @@ public class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw()
{
throw new DuckTypeProxyTypeDefinitionIsNull();
@ -54,7 +76,7 @@ public class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
/// <summary>
/// DuckType target object instance is null
/// </summary>
public class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
internal class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
{
private DuckTypeTargetObjectInstanceIsNull()
: base($"The target object instance is null.")
@ -62,6 +84,7 @@ public class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw()
{
throw new DuckTypeTargetObjectInstanceIsNull();
@ -71,7 +94,7 @@ public class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
/// <summary>
/// DuckType invalid type conversion exception
/// </summary>
public class DuckTypeInvalidTypeConversionException : DuckTypeException
internal class DuckTypeInvalidTypeConversionException : DuckTypeException
{
private DuckTypeInvalidTypeConversionException(Type actualType, Type expectedType)
: base($"Invalid type conversion from {actualType.FullName} to {expectedType.FullName}")
@ -79,6 +102,7 @@ public class DuckTypeInvalidTypeConversionException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(Type actualType, Type expectedType)
{
throw new DuckTypeInvalidTypeConversionException(actualType, expectedType);
@ -88,7 +112,7 @@ public class DuckTypeInvalidTypeConversionException : DuckTypeException
/// <summary>
/// DuckType property can't be read
/// </summary>
public class DuckTypePropertyCantBeReadException : DuckTypeException
internal class DuckTypePropertyCantBeReadException : DuckTypeException
{
private DuckTypePropertyCantBeReadException(PropertyInfo property)
: base($"The property '{property.Name}' can't be read, you should remove the getter from the proxy definition base type class or interface.")
@ -96,6 +120,7 @@ public class DuckTypePropertyCantBeReadException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property)
{
throw new DuckTypePropertyCantBeReadException(property);
@ -105,7 +130,7 @@ public class DuckTypePropertyCantBeReadException : DuckTypeException
/// <summary>
/// DuckType property can't be written
/// </summary>
public class DuckTypePropertyCantBeWrittenException : DuckTypeException
internal class DuckTypePropertyCantBeWrittenException : DuckTypeException
{
private DuckTypePropertyCantBeWrittenException(PropertyInfo property)
: base($"The property '{property.Name}' can't be written, you should remove the setter from the proxy definition base type class or interface.")
@ -113,6 +138,7 @@ public class DuckTypePropertyCantBeWrittenException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property)
{
throw new DuckTypePropertyCantBeWrittenException(property);
@ -122,7 +148,7 @@ public class DuckTypePropertyCantBeWrittenException : DuckTypeException
/// <summary>
/// DuckType property argument doesn't have the same argument length
/// </summary>
public class DuckTypePropertyArgumentsLengthException : DuckTypeException
internal class DuckTypePropertyArgumentsLengthException : DuckTypeException
{
private DuckTypePropertyArgumentsLengthException(PropertyInfo property)
: base($"The property '{property.Name}' doesn't have the same number of arguments as the original property.")
@ -130,6 +156,7 @@ public class DuckTypePropertyArgumentsLengthException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property)
{
throw new DuckTypePropertyArgumentsLengthException(property);
@ -139,7 +166,7 @@ public class DuckTypePropertyArgumentsLengthException : DuckTypeException
/// <summary>
/// DuckType field is readonly
/// </summary>
public class DuckTypeFieldIsReadonlyException : DuckTypeException
internal class DuckTypeFieldIsReadonlyException : DuckTypeException
{
private DuckTypeFieldIsReadonlyException(FieldInfo field)
: base($"The field '{field.Name}' is marked as readonly, you should remove the setter from the base type class or interface.")
@ -147,6 +174,7 @@ public class DuckTypeFieldIsReadonlyException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(FieldInfo field)
{
throw new DuckTypeFieldIsReadonlyException(field);
@ -156,41 +184,25 @@ public class DuckTypeFieldIsReadonlyException : DuckTypeException
/// <summary>
/// DuckType property or field not found
/// </summary>
public class DuckTypePropertyOrFieldNotFoundException : DuckTypeException
internal class DuckTypePropertyOrFieldNotFoundException : DuckTypeException
{
private DuckTypePropertyOrFieldNotFoundException(string name, string duckAttributeName)
: base($"The property or field '{duckAttributeName}' for the proxy property '{name}' was not found in the instance.")
private DuckTypePropertyOrFieldNotFoundException(string name, string duckAttributeName, string type)
: base($"The property or field '{duckAttributeName}' for the proxy property '{name}' was not found in the instance of type '{type}'.")
{
}
[DebuggerHidden]
internal static void Throw(string name, string duckAttributeName)
[DoesNotReturn]
internal static void Throw(string name, string duckAttributeName, Type type)
{
throw new DuckTypePropertyOrFieldNotFoundException(name, duckAttributeName);
}
}
/// <summary>
/// DuckType type is not public exception
/// </summary>
public class DuckTypeTypeIsNotPublicException : DuckTypeException
{
private DuckTypeTypeIsNotPublicException(Type type, string argumentName)
: base($"The type '{type.FullName}' must be public, argument: '{argumentName}'")
{
}
[DebuggerHidden]
internal static void Throw(Type type, string argumentName)
{
throw new DuckTypeTypeIsNotPublicException(type, argumentName);
throw new DuckTypePropertyOrFieldNotFoundException(name, duckAttributeName, type?.FullName ?? type?.Name ?? "NULL");
}
}
/// <summary>
/// DuckType struct members cannot be changed exception
/// </summary>
public class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
internal class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
{
private DuckTypeStructMembersCannotBeChangedException(Type type)
: base($"Modifying struct members is not supported. [{type.FullName}]")
@ -198,6 +210,7 @@ public class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(Type type)
{
throw new DuckTypeStructMembersCannotBeChangedException(type);
@ -207,7 +220,7 @@ public class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
/// <summary>
/// DuckType target method can not be found exception
/// </summary>
public class DuckTypeTargetMethodNotFoundException : DuckTypeException
internal class DuckTypeTargetMethodNotFoundException : DuckTypeException
{
private DuckTypeTargetMethodNotFoundException(MethodInfo method)
: base($"The target method for the proxy method '{method}' was not found.")
@ -215,6 +228,7 @@ public class DuckTypeTargetMethodNotFoundException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo method)
{
throw new DuckTypeTargetMethodNotFoundException(method);
@ -224,7 +238,7 @@ public class DuckTypeTargetMethodNotFoundException : DuckTypeException
/// <summary>
/// DuckType proxy method parameter is missing exception
/// </summary>
public class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException
internal class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException
{
private DuckTypeProxyMethodParameterIsMissingException(MethodInfo proxyMethod, ParameterInfo targetParameterInfo)
: base($"The proxy method '{proxyMethod.Name}' is missing parameter '{targetParameterInfo.Name}' declared in the target method.")
@ -232,6 +246,7 @@ public class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, ParameterInfo targetParameterInfo)
{
throw new DuckTypeProxyMethodParameterIsMissingException(proxyMethod, targetParameterInfo);
@ -241,7 +256,7 @@ public class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException
/// <summary>
/// DuckType parameter signature mismatch between proxy and target method
/// </summary>
public class DuckTypeProxyAndTargetMethodParameterSignatureMismatchException : DuckTypeException
internal class DuckTypeProxyAndTargetMethodParameterSignatureMismatchException : DuckTypeException
{
private DuckTypeProxyAndTargetMethodParameterSignatureMismatchException(MethodInfo proxyMethod, MethodInfo targetMethod)
: base($"Parameter signature mismatch between proxy '{proxyMethod}' and target method '{targetMethod}'")
@ -249,16 +264,35 @@ public class DuckTypeProxyAndTargetMethodParameterSignatureMismatchException : D
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod)
{
throw new DuckTypeProxyAndTargetMethodParameterSignatureMismatchException(proxyMethod, targetMethod);
}
}
/// <summary>
/// DuckType parameter signature mismatch between proxy and target method
/// </summary>
internal class DuckTypeProxyAndTargetMethodReturnTypeMismatchException : DuckTypeException
{
private DuckTypeProxyAndTargetMethodReturnTypeMismatchException(MethodInfo proxyMethod, MethodInfo targetMethod)
: base($"Return type mismatch between proxy '{proxyMethod}' and target method '{targetMethod}'.")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod)
{
throw new DuckTypeProxyAndTargetMethodReturnTypeMismatchException(proxyMethod, targetMethod);
}
}
/// <summary>
/// DuckType proxy methods with generic parameters are not supported in non public instances exception
/// </summary>
public class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException : DuckTypeException
internal class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException : DuckTypeException
{
private DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException(MethodInfo proxyMethod)
: base($"The proxy method with generic parameters '{proxyMethod}' are not supported on non public instances")
@ -266,6 +300,7 @@ public class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicIns
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod)
{
throw new DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException(proxyMethod);
@ -275,7 +310,7 @@ public class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicIns
/// <summary>
/// DuckType proxy method has an ambiguous match in the target type exception
/// </summary>
public class DuckTypeTargetMethodAmbiguousMatchException : DuckTypeException
internal class DuckTypeTargetMethodAmbiguousMatchException : DuckTypeException
{
private DuckTypeTargetMethodAmbiguousMatchException(MethodInfo proxyMethod, MethodInfo targetMethod, MethodInfo targetMethod2)
: base($"The proxy method '{proxyMethod}' matches at least two methods in the target type. Method1 = '{targetMethod}' and Method2 = '{targetMethod2}'")
@ -283,8 +318,172 @@ public class DuckTypeTargetMethodAmbiguousMatchException : DuckTypeException
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod, MethodInfo targetMethod2)
{
throw new DuckTypeTargetMethodAmbiguousMatchException(proxyMethod, targetMethod, targetMethod2);
}
}
/// <summary>
/// DuckType reverse proxy type to derive from is a struct exception
/// </summary>
internal class DuckTypeReverseProxyBaseIsStructException : DuckTypeException
{
private DuckTypeReverseProxyBaseIsStructException(Type type)
: base($"Cannot derive from struct type '{type.FullName}' for reverse proxy")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(Type type)
{
throw new DuckTypeReverseProxyBaseIsStructException(type);
}
}
/// <summary>
/// DuckType proxy method is abstract
/// </summary>
internal class DuckTypeReverseProxyImplementorIsAbstractOrInterfaceException : DuckTypeException
{
private DuckTypeReverseProxyImplementorIsAbstractOrInterfaceException(Type type)
: base($"The implementation type '{type.FullName}' must not be an interface or abstract type for reverse proxy")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(Type type)
{
throw new DuckTypeReverseProxyImplementorIsAbstractOrInterfaceException(type);
}
}
/// <summary>
/// DuckType property can't be read
/// </summary>
internal class DuckTypeReverseProxyPropertyCannotBeAbstractException : DuckTypeException
{
private DuckTypeReverseProxyPropertyCannotBeAbstractException(PropertyInfo property)
: base($"The property '{property.Name}' cannot be abstract for reverse proxy")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property)
{
throw new DuckTypeReverseProxyPropertyCannotBeAbstractException(property);
}
}
/// <summary>
/// DuckType method was [DuckReverseMethod] in non-reverse proxy
/// </summary>
internal class DuckTypeIncorrectReverseMethodUsageException : DuckTypeException
{
private DuckTypeIncorrectReverseMethodUsageException(MethodInfo method)
: base($"The method '{method.Name}' was marked as a [DuckReverseMethod] but not doing reverse duck typing.")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo method)
{
throw new DuckTypeIncorrectReverseMethodUsageException(method);
}
}
/// <summary>
/// DuckType property was [DuckReverseMethod] in non-reverse proxy
/// </summary>
internal class DuckTypeIncorrectReversePropertyUsageException : DuckTypeException
{
private DuckTypeIncorrectReversePropertyUsageException(PropertyInfo property)
: base($"The property '{property.Name}' was marked as a [DuckReverseMethod] but not doing reverse duck typing.")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property)
{
throw new DuckTypeIncorrectReversePropertyUsageException(property);
}
}
/// <summary>
/// DuckType proxy was missing an implementation
/// </summary>
internal class DuckTypeReverseProxyMissingPropertyImplementationException : DuckTypeException
{
private DuckTypeReverseProxyMissingPropertyImplementationException(IEnumerable<PropertyInfo> properties)
: base($"The duck reverse proxy was missing implementations for properties: {string.Join(", ", properties.Select(x => x.Name))}")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(IEnumerable<PropertyInfo> properties)
{
throw new DuckTypeReverseProxyMissingPropertyImplementationException(properties);
}
}
/// <summary>
/// DuckType proxy was missing an implementation
/// </summary>
internal class DuckTypeReverseProxyMissingMethodImplementationException : DuckTypeException
{
private DuckTypeReverseProxyMissingMethodImplementationException(IEnumerable<MethodInfo> methods)
: base($"The duck reverse proxy was missing implementations for methods: {string.Join(", ", methods.Select(x => x.Name))}")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(IEnumerable<MethodInfo> methods)
{
throw new DuckTypeReverseProxyMissingMethodImplementationException(methods);
}
}
/// <summary>
/// DuckType proxy tried to implement a generic method in a non-generic way
/// </summary>
internal class DuckTypeReverseAttributeParameterNamesMismatchException : DuckTypeException
{
private DuckTypeReverseAttributeParameterNamesMismatchException(MethodInfo method)
: base($"The reverse duck attribute parameter names for method '{method.Name}' did not match the method's parameters ")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo method)
{
throw new DuckTypeReverseAttributeParameterNamesMismatchException(method);
}
}
/// <summary>
/// DuckType proxy tried to implement a generic method in a non-generic way
/// </summary>
internal class DuckTypeReverseProxyMustImplementGenericMethodAsGenericException : DuckTypeException
{
private DuckTypeReverseProxyMustImplementGenericMethodAsGenericException(MethodInfo implementationMethod, MethodInfo targetMethod)
: base($"The duck reverse proxy implementation '{implementationMethod.Name}' for generic target method '{targetMethod.Name}' " +
$"must have same number of generic parameters - had {implementationMethod.GetGenericArguments().Length}, expected {targetMethod.GetGenericArguments().Length}")
{
}
[DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo implementationMethod, MethodInfo targetMethod)
{
throw new DuckTypeReverseProxyMustImplementGenericMethodAsGenericException(implementationMethod, targetMethod);
}
}

View File

@ -15,6 +15,7 @@
// </copyright>
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
@ -22,7 +23,7 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Duck type extensions
/// </summary>
public static class DuckTypeExtensions
internal static class DuckTypeExtensions
{
/// <summary>
/// Gets the duck type instance for the object implementing a base class or interface T
@ -59,14 +60,11 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (DuckType.CreateCache<T>.IsVisible)
DuckType.CreateTypeResult proxyResult = DuckType.CreateCache<T>.GetProxy(instance.GetType());
if (proxyResult.Success)
{
DuckType.CreateTypeResult proxyResult = DuckType.CreateCache<T>.GetProxy(instance.GetType());
if (proxyResult.Success)
{
value = proxyResult.CreateInstance<T>(instance);
return true;
}
value = proxyResult.CreateInstance<T>(instance)!;
return true;
}
value = default;
@ -88,7 +86,7 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
if (targetType != null)
{
DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
if (proxyResult.Success)
@ -117,13 +115,10 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (DuckType.CreateCache<T>.IsVisible)
DuckType.CreateTypeResult proxyResult = DuckType.CreateCache<T>.GetProxy(instance.GetType());
if (proxyResult.Success)
{
DuckType.CreateTypeResult proxyResult = DuckType.CreateCache<T>.GetProxy(instance.GetType());
if (proxyResult.Success)
{
return proxyResult.CreateInstance<T>(instance);
}
return proxyResult.CreateInstance<T>(instance);
}
return null;
@ -143,7 +138,7 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
if (targetType != null)
{
DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
if (proxyResult.Success)
@ -169,12 +164,7 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (DuckType.CreateCache<T>.IsVisible)
{
return DuckType.CanCreate<T>(instance);
}
return false;
return DuckType.CanCreate<T>(instance);
}
/// <summary>
@ -191,11 +181,53 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
if (targetType != null)
{
return DuckType.CanCreate(targetType, instance);
}
return false;
}
/// <summary>
/// Gets or creates a proxy that implements/derives from <paramref name="typeToDeriveFrom"/>,
/// and delegates implementations/overrides to <paramref name="instance"/>
/// </summary>
/// <param name="instance">The instance containing additional overrides/implementations</param>
/// <param name="typeToDeriveFrom">The type to derive from</param>
/// <returns>DuckType instance</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static object DuckImplement(this object instance, Type typeToDeriveFrom)
=> DuckType.CreateReverse(typeToDeriveFrom, instance);
/// <summary>
/// Tries to create a proxy that implements/derives from <paramref name="typeToDeriveFrom"/>,
/// and delegates implementations/overrides to <paramref name="instance"/>
/// ducktype the object implementing a base class or interface T
/// </summary>
/// <param name="instance">The instance containing additional overrides/implementations</param>
/// <param name="typeToDeriveFrom">The type to derive from</param>
/// <param name="value">The Ducktype instance</param>
/// <returns>true if the object instance was ducktyped; otherwise, false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryDuckImplement(this object instance, Type typeToDeriveFrom, out object value)
{
if (instance is null)
{
DuckTypeTargetObjectInstanceIsNull.Throw();
}
if (typeToDeriveFrom != null)
{
DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateReverseProxyType(typeToDeriveFrom, instance.GetType());
if (proxyResult.Success)
{
value = proxyResult.CreateInstance(instance);
return true;
}
}
value = default;
return false;
}
}

View File

@ -15,12 +15,15 @@
// </copyright>
using System;
using System.ComponentModel;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Duck type interface
/// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IDuckType
{
/// <summary>
@ -32,4 +35,10 @@ public interface IDuckType
/// Gets instance Type
/// </summary>
Type Type { get; }
/// <summary>
/// Calls ToString() on the instance
/// </summary>
/// <returns>ToString result</returns>
string ToString();
}

View File

@ -25,15 +25,16 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary>
/// Internal IL Helpers
/// </summary>
// ReSharper disable once InconsistentNaming
internal static class ILHelpersExtensions
{
private static List<DynamicMethod> _dynamicMethods = new List<DynamicMethod>();
private static readonly List<DynamicMethod> DynamicMethods = new();
internal static DynamicMethod GetDynamicMethodForIndex(int index)
{
lock (_dynamicMethods)
lock (DynamicMethods)
{
return _dynamicMethods[index];
return DynamicMethods[index];
}
}
@ -62,8 +63,14 @@ internal static class ILHelpersExtensions
methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
delType = delegateType.CreateTypeInfo().AsType();
invokeMethod = delType.GetMethod("Invoke");
var delegateTypeInfo = delegateType.CreateTypeInfo();
if (delegateTypeInfo is null)
{
DuckTypeException.Throw($"Error creating the delegate type info for {delegateType.FullName}");
}
delType = delegateTypeInfo.AsType();
invokeMethod = delType.GetMethod("Invoke")!;
}
/// <summary>
@ -345,11 +352,49 @@ internal static class ILHelpersExtensions
}
else if (expectedUnderlyingType != typeof(object))
{
// WARNING: If the actual type cannot be cast to expectedUnderlyingType,
// this will throw an exception at runtime when accessing the member
il.Emit(OpCodes.Castclass, expectedUnderlyingType);
}
}
}
// WARNING: This method is a slim version of the WriteTypeConversion method without IL
// Checks in both method must match! if you change either, you need to change both
internal static void CheckTypeConversion(Type actualType, Type expectedType)
{
var actualUnderlyingType = actualType.IsEnum ? Enum.GetUnderlyingType(actualType) : actualType;
var expectedUnderlyingType = expectedType.IsEnum ? Enum.GetUnderlyingType(expectedType) : expectedType;
if (actualUnderlyingType == expectedUnderlyingType)
{
return;
}
if (actualUnderlyingType.IsValueType)
{
if (expectedUnderlyingType.IsValueType)
{
// If both underlying types are value types then both must be of the same type.
DuckTypeInvalidTypeConversionException.Throw(actualType, expectedType);
}
else if (expectedUnderlyingType != typeof(object) && !expectedUnderlyingType.IsAssignableFrom(actualUnderlyingType))
{
// If the expected type can't be assigned from the actual value type.
// Means if the expected type is an interface the actual type doesn't implement it.
// So no possible conversion or casting can be made here.
DuckTypeInvalidTypeConversionException.Throw(actualType, expectedType);
}
}
else if (expectedUnderlyingType.IsValueType)
{
if (actualUnderlyingType != typeof(object) && !actualUnderlyingType.IsAssignableFrom(expectedUnderlyingType))
{
DuckTypeInvalidTypeConversionException.Throw(actualType, expectedType);
}
}
}
/// <summary>
/// Write a Call to a method using Calli
/// </summary>
@ -364,7 +409,7 @@ internal static class ILHelpersExtensions
method.CallingConvention,
method.ReturnType,
method.GetParameters().Select(p => p.ParameterType).ToArray(),
null);
null!);
}
/// <summary>
@ -375,25 +420,31 @@ internal static class ILHelpersExtensions
/// <param name="proxyType">ProxyType builder</param>
internal static void WriteDynamicMethodCall(this LazyILGenerator il, DynamicMethod dynamicMethod, TypeBuilder proxyType)
{
if (proxyType is null)
{
return;
}
// We create a custom delegate inside the module builder
CreateDelegateTypeFor(proxyType, dynamicMethod, out Type delegateType, out MethodInfo invokeMethod);
int index;
lock (_dynamicMethods)
lock (DynamicMethods)
{
_dynamicMethods.Add(dynamicMethod);
index = _dynamicMethods.Count - 1;
DynamicMethods.Add(dynamicMethod);
index = DynamicMethods.Count - 1;
}
// We fill the DelegateCache<> for that custom type with the delegate instance
MethodInfo fillDelegateMethodInfo = typeof(DuckType.DelegateCache<>).MakeGenericType(delegateType).GetMethod("FillDelegate", BindingFlags.NonPublic | BindingFlags.Static);
fillDelegateMethodInfo.Invoke(null, new object[] { index });
var delegateCacheType = typeof(DuckType.DelegateCache<>).MakeGenericType(delegateType);
MethodInfo fillDelegateMethodInfo = delegateCacheType.GetMethod("FillDelegate", BindingFlags.NonPublic | BindingFlags.Static)!;
fillDelegateMethodInfo?.Invoke(null, new object[] { index });
// We get the delegate instance and load it in to the stack before the parameters (at the begining of the IL body)
il.SetOffset(0);
il.EmitCall(OpCodes.Call, typeof(DuckType.DelegateCache<>).MakeGenericType(delegateType).GetMethod("GetDelegate"), null);
il.EmitCall(OpCodes.Call, delegateCacheType.GetMethod("GetDelegate")!, null!);
il.ResetOffset();
// We emit the call to the delegate invoke method.
il.EmitCall(OpCodes.Callvirt, invokeMethod, null);
il.EmitCall(OpCodes.Callvirt, invokeMethod, null!);
}
}

View File

@ -14,15 +14,14 @@
// limitations under the License.
// </copyright>
using System;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices;
/// <summary>
/// This attribute is recognized by the CLR and allow us to disable visibility checks for certain assemblies (only from 4.6+)
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class IgnoresAccessChecksToAttribute : Attribute
internal class IgnoresAccessChecksToAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="IgnoresAccessChecksToAttribute"/> class.

View File

@ -21,10 +21,11 @@ using System.Reflection.Emit;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
// ReSharper disable once InconsistentNaming
internal class LazyILGenerator
{
private ILGenerator _generator;
private List<Action<ILGenerator>> _instructions;
private readonly ILGenerator _generator;
private readonly List<Action<ILGenerator>> _instructions;
private int _offset;
public LazyILGenerator(ILGenerator generator)
@ -70,17 +71,17 @@ internal class LazyILGenerator
public LocalBuilder DeclareLocal(Type localType, bool pinned)
{
return _generator.DeclareLocal(localType, pinned);
return _generator?.DeclareLocal(localType, pinned);
}
public LocalBuilder DeclareLocal(Type localType)
{
return _generator.DeclareLocal(localType);
return _generator?.DeclareLocal(localType);
}
public Label DefineLabel()
{
return _generator.DefineLabel();
return _generator?.DefineLabel() ?? default;
}
public void Emit(OpCode opcode, string str)
@ -449,9 +450,12 @@ internal class LazyILGenerator
public void Flush()
{
foreach (Action<ILGenerator> instr in _instructions)
if (_generator is not null)
{
instr(_generator);
foreach (Action<ILGenerator> instruction in _instructions)
{
instruction(_generator);
}
}
_instructions.Clear();

View File

@ -0,0 +1,182 @@
// <copyright file="System.Diagnostics.CodeAnalysis.Attributes.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// https://github.com/dotnet/runtime/blob/bffa7cf52b3982597adc5447c25e7aaa3b063c1c/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
// This file contains attributes from the System.Diagnostics.CodeAnalysis namespace
// used by the compiler for null-state static analysis.
// This is a C# feature, but requires these attributes to be defined,
// so we define them here for older .NET runtimes.
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis
#pragma warning disable SA1649 // file name should match first type name
#pragma warning disable SA1402 // file may only contain a single type
// ReSharper disable once CheckNamespace
namespace System.Diagnostics.CodeAnalysis;
#if !NETCOREAPP3_0_OR_GREATER
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property)]
internal sealed class AllowNullAttribute : Attribute
{
}
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property)]
internal sealed class DisallowNullAttribute : Attribute
{
}
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]
internal sealed class MaybeNullAttribute : Attribute
{
}
/// <summary>Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]
internal sealed class NotNullAttribute : Attribute
{
}
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class MaybeNullWhenAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="MaybeNullWhenAttribute"/> class with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets a value indicating whether the associated parameter may be null.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="NotNullWhenAttribute"/> class with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets a value indicating whether the associated parameter will not be null.</summary>
public bool ReturnValue { get; }
}
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true)]
internal sealed class NotNullIfNotNullAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="NotNullIfNotNullAttribute"/> class with the associated parameter name.</summary>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
/// <summary>Gets the associated parameter name.</summary>
public string ParameterName { get; }
}
/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class DoesNotReturnAttribute : Attribute
{
}
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class DoesNotReturnIfAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="DoesNotReturnIfAttribute"/> class with the specified parameter value.</summary>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
/// <summary>Gets a value indicating whether the method will not return if the associated Boolean parameter is passed the specified value.</summary>
public bool ParameterValue { get; }
}
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="MemberNotNullAttribute"/> class with a field or property member.</summary>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
public MemberNotNullAttribute(string member) => Members = new[] { member };
/// <summary>Initializes a new instance of the <see cref="MemberNotNullAttribute"/> class with the list of field and property members.</summary>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
public MemberNotNullAttribute(params string[] members) => Members = members;
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
}
#endif
#if !NET5_0_OR_GREATER
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="MemberNotNullWhenAttribute"/> class with the specified return value condition and a field or property member.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new[] { member };
}
/// <summary>Initializes a new instance of the <see cref="MemberNotNullWhenAttribute"/> class with the specified return value condition and list of field and property members.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
/// <summary>Gets a value indicating whether the return value will be null or not.</summary>
public bool ReturnValue { get; }
/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
}
#endif
#pragma warning restore SA1402
#pragma warning restore SA1649

View File

@ -0,0 +1,86 @@
// <copyright file="ThrowHelper.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace OpenTelemetry.AutoInstrumentation.Util;
internal class ThrowHelper
{
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowArgumentNullException(string paramName) => throw new ArgumentNullException(paramName);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(string paramName) => throw new ArgumentOutOfRangeException(paramName);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(string paramName, string message) => throw new ArgumentOutOfRangeException(paramName, message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowArgumentOutOfRangeException(string paramName, object actualValue, string message) => throw new ArgumentOutOfRangeException(paramName, actualValue, message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowArgumentException(string message) => throw new ArgumentException(message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowArgumentException(string message, string paramName) => throw new ArgumentException(message, paramName);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowInvalidOperationException(string message) => throw new InvalidOperationException(message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowException(string message) => throw new Exception(message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowInvalidCastException(string message) => throw new InvalidCastException(message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowNotSupportedException(string message) => throw new NotSupportedException(message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowKeyNotFoundException(string message) => throw new KeyNotFoundException(message);
[MethodImpl(MethodImplOptions.NoInlining)]
[DebuggerHidden]
[DoesNotReturn]
internal static void ThrowNullReferenceException(string message) => throw new NullReferenceException(message);
}