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.CallTargetInvoker
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn.CallTargetReturn() -> void 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.CallTargetState(System.Diagnostics.Activity activity, object state, System.DateTimeOffset? startTime) -> void
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.StartTime.get -> System.DateTimeOffset? OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.StartTime.get -> System.DateTimeOffset?
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.State.get -> object 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
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CanCreate() -> bool OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CanCreate() -> bool
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateInstance<T>(object instance) -> T 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.CreateTypeResult() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.ProxyType.get -> System.Type OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.ProxyType.get -> System.Type
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.DelegateCache<TProxyDelegate> 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
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.ToString() -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Type.get -> System.Type 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
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.Column -> int OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.Column -> int
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.ErrorLocationStruct() -> void 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.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(System.Type proxyType, object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CanCreate<T>(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.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>.CanCreate(object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.Create(object instance) -> T 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.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.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.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.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 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.CreateCache<T>.Type -> System.Type
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo -> System.Reflection.MethodInfo static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo.get -> System.Reflection.MethodInfo
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo -> 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.CallTargetInvoker
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetReturn.CallTargetReturn() -> void 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.CallTargetState(System.Diagnostics.Activity activity, object state, System.DateTimeOffset? startTime) -> void
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.StartTime.get -> System.DateTimeOffset? OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.StartTime.get -> System.DateTimeOffset?
OpenTelemetry.AutoInstrumentation.CallTarget.CallTargetState.State.get -> object 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
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T> OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CanCreate() -> bool OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CanCreate() -> bool
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.CreateInstance<T>(object instance) -> T 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.CreateTypeResult() -> void
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.ProxyType.get -> System.Type OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateTypeResult.ProxyType.get -> System.Type
OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.DelegateCache<TProxyDelegate> 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
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Instance.get -> object
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.ToString() -> string
OpenTelemetry.AutoInstrumentation.DuckTyping.IDuckType.Type.get -> System.Type 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
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.Column -> int OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.Column -> int
OpenTelemetry.AutoInstrumentation.Instrumentations.GraphQL.ErrorLocationStruct.ErrorLocationStruct() -> void 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.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(System.Type proxyType, object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CanCreate<T>(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.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>.CanCreate(object instance) -> bool
static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.CreateCache<T>.Create(object instance) -> T 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.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.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.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.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 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.CreateCache<T>.Type -> System.Type
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo -> System.Reflection.MethodInfo static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.EnumToObjectMethodInfo.get -> System.Reflection.MethodInfo
static readonly OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo -> System.Reflection.MethodInfo static OpenTelemetry.AutoInstrumentation.DuckTyping.DuckType.GetTypeFromHandleMethodInfo.get -> System.Reflection.MethodInfo

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
// </copyright> // </copyright>
using System;
using System.Reflection; using System.Reflection;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping; namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
@ -22,7 +21,7 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// Duck kind /// Duck kind
/// </summary> /// </summary>
public enum DuckKind internal enum DuckKind
{ {
/// <summary> /// <summary>
/// Property /// Property
@ -38,41 +37,15 @@ public enum DuckKind
/// <summary> /// <summary>
/// Duck attribute /// Duck attribute
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field, AllowMultiple = false)] internal class DuckAttribute : DuckAttributeBase
public class DuckAttribute : Attribute
{ {
/// <summary> /// <summary>
/// Default BindingFlags /// Default BindingFlags
/// </summary> /// </summary>
public const BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy; 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> /// <summary>
/// Gets or sets duck kind /// Gets or sets duck kind
/// </summary> /// </summary>
public DuckKind Kind { get; set; } = DuckKind.Property; 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 /// Duck copy struct attribute
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
public class DuckCopyAttribute : Attribute internal class DuckCopyAttribute : Attribute
{ {
} }

View File

@ -19,7 +19,7 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// Duck attribute where the underlying member is a field /// Duck attribute where the underlying member is a field
/// </summary> /// </summary>
public class DuckFieldAttribute : DuckAttribute internal class DuckFieldAttribute : DuckAttribute
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DuckFieldAttribute"/> class. /// 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 /// Ignores the member when DuckTyping
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field, AllowMultiple = false)] [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 /// Use to include a member that would normally be ignored
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class DuckIncludeAttribute : Attribute internal class DuckIncludeAttribute : Attribute
{ {
} }

View File

@ -14,34 +14,11 @@
// limitations under the License. // limitations under the License.
// </copyright> // </copyright>
using System;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping; namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// Duck reverse method attribute /// Duck reverse method attribute
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Method)] internal class DuckReverseMethodAttribute : DuckAttributeBase
public class DuckReverseMethodAttribute : Attribute
{ {
/// <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> /// </summary>
public static partial class DuckType 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; string proxyMemberName = proxyMember.Name;
Type proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType : proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object); 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, "get_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
proxyMemberReturnType, proxyMemberReturnType,
Type.EmptyTypes); Type.EmptyTypes);
LazyILGenerator il = new LazyILGenerator(proxyMethod.GetILGenerator()); LazyILGenerator il = new LazyILGenerator(proxyMethod?.GetILGenerator());
Type returnType = targetField.FieldType; Type returnType = targetField.FieldType;
// Load the instance // Load the instance
if (!targetField.IsStatic) if (!targetField.IsStatic)
{ {
il.Emit(OpCodes.Ldarg_0); 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 // Load the field value to the stack
@ -52,7 +60,7 @@ public static partial class DuckType
// In case is public is pretty simple // In case is public is pretty simple
il.Emit(targetField.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, targetField); 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 // 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). // 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 // Emit the call to the dynamic method
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder); 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 // Check if the type can be converted or if we need to enable duck chaining
if (NeedsDuckChaining(targetField.FieldType, proxyMemberReturnType)) if (NeedsDuckChaining(targetField.FieldType, proxyMemberReturnType))
{ {
if (UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType) && targetField.FieldType.IsValueType) UseDirectAccessTo(proxyTypeBuilder, targetField.FieldType);
{
il.Emit(OpCodes.Box, 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() // We call DuckType.CreateCache<>.Create()
MethodInfo getProxyMethodInfo = typeof(CreateCache<>) MethodIlHelper.AddIlToDuckChain(il, proxyMemberReturnType, targetField.FieldType);
.MakeGenericType(proxyMemberReturnType).GetMethod("Create");
il.Emit(OpCodes.Call, getProxyMethodInfo);
} }
else if (returnType != proxyMemberReturnType) else if (returnType != proxyMemberReturnType)
{ {
@ -108,29 +118,41 @@ public static partial class DuckType
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
il.Flush(); il.Flush();
_methodBuilderGetToken.Invoke(proxyMethod, null); if (proxyMethod is not null)
{
MethodBuilderGetToken.Invoke(proxyMethod, null);
}
return proxyMethod; 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; string proxyMemberName = proxyMember.Name;
Type proxyMemberReturnType = proxyMember is PropertyInfo pinfo ? pinfo.PropertyType : proxyMember is FieldInfo finfo ? finfo.FieldType : typeof(object); 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, "set_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
typeof(void), typeof(void),
new[] { proxyMemberReturnType }); new[] { proxyMemberReturnType });
LazyILGenerator il = new LazyILGenerator(method.GetILGenerator()); LazyILGenerator il = new LazyILGenerator(method?.GetILGenerator());
Type currentValueType = proxyMemberReturnType; Type currentValueType = proxyMemberReturnType;
// Load instance // Load instance
if (!targetField.IsStatic) if (!targetField.IsStatic)
{ {
il.Emit(OpCodes.Ldarg_0); 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 // 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)); il.WriteTypeConversion(proxyMemberReturnType, typeof(IDuckType));
// Call IDuckType.Instance property to get the actual value // 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); currentValueType = typeof(object);
} }
@ -159,10 +181,9 @@ public static partial class DuckType
il.Emit(targetField.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, targetField); 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 // 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}"; string dynMethodName = $"_setField_{targetField.DeclaringType.Name}_{targetField.Name}";
// Convert the field type for the dynamic method // Convert the field type for the dynamic method
@ -200,10 +221,21 @@ public static partial class DuckType
// Emit the call to the dynamic method // Emit the call to the dynamic method
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder); 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.Emit(OpCodes.Ret);
il.Flush(); il.Flush();
_methodBuilderGetToken.Invoke(method, null); if (method is not null)
{
MethodBuilderGetToken.Invoke(method, null);
}
return method; return method;
} }
} }

View File

@ -27,8 +27,21 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// </summary> /// </summary>
public static partial class DuckType 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; string proxyMemberName = proxyMember.Name;
Type proxyMemberReturnType = typeof(object); Type proxyMemberReturnType = typeof(object);
Type[] proxyParameterTypes = Type.EmptyTypes; Type[] proxyParameterTypes = Type.EmptyTypes;
@ -53,21 +66,23 @@ public static partial class DuckType
} }
} }
MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod( MethodBuilder proxyMethod = proxyTypeBuilder?.DefineMethod(
"get_" + proxyMemberName, "get_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
proxyMemberReturnType, proxyMemberReturnType,
proxyParameterTypes); proxyParameterTypes);
LazyILGenerator il = new LazyILGenerator(proxyMethod.GetILGenerator()); LazyILGenerator il = new LazyILGenerator(proxyMethod?.GetILGenerator());
MethodInfo targetMethod = targetProperty.GetMethod;
Type returnType = targetProperty.PropertyType; Type returnType = targetProperty.PropertyType;
// Load the instance if needed // Load the instance if needed
if (!targetMethod.IsStatic) if (!targetMethod.IsStatic)
{ {
il.Emit(OpCodes.Ldarg_0); 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 // Load the indexer keys to the stack
@ -84,7 +99,7 @@ public static partial class DuckType
il.Emit(OpCodes.Castclass, typeof(IDuckType)); il.Emit(OpCodes.Castclass, typeof(IDuckType));
// Call IDuckType.Instance property to get the actual value // 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); targetParamType = typeof(object);
} }
else else
@ -108,7 +123,7 @@ public static partial class DuckType
if (targetMethod.IsPublic) if (targetMethod.IsPublic)
{ {
// We can emit a normal call if we have a public instance with a public property method. // 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 else
{ {
@ -116,7 +131,7 @@ public static partial class DuckType
il.WriteMethodCalli(targetMethod); 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 // 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). // 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.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.WriteTypeConversion(targetProperty.PropertyType, returnType);
dynIL.Emit(OpCodes.Ret); dynIL.Emit(OpCodes.Ret);
dynIL.Flush(); dynIL.Flush();
@ -151,21 +166,29 @@ public static partial class DuckType
// Emit the call to the dynamic method // Emit the call to the dynamic method
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder); 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 // Handle the return value
// Check if the type can be converted or if we need to enable duck chaining // 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) UseDirectAccessTo(proxyTypeBuilder, targetProperty.PropertyType);
{
il.Emit(OpCodes.Box, targetProperty.PropertyType);
}
// We call DuckType.CreateCache<>.Create() // If this is a forward duck type, we need to create a duck type from the original instance
MethodInfo getProxyMethodInfo = typeof(CreateCache<>) // If this is a reverse duck type, we need to cast to IDuckType and extract the original instance
.MakeGenericType(proxyMemberReturnType).GetMethod("Create"); duckCastInnerToOuterFunc(il, proxyMemberReturnType, targetProperty.PropertyType);
il.Emit(OpCodes.Call, getProxyMethodInfo);
} }
else if (returnType != proxyMemberReturnType) else if (returnType != proxyMemberReturnType)
{ {
@ -175,12 +198,29 @@ public static partial class DuckType
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
il.Flush(); il.Flush();
_methodBuilderGetToken.Invoke(proxyMethod, null); if (proxyMethod is not null)
{
MethodBuilderGetToken.Invoke(proxyMethod, null);
}
return proxyMethod; 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; string proxyMemberName = null;
Type[] proxyParameterTypes = Type.EmptyTypes; Type[] proxyParameterTypes = Type.EmptyTypes;
Type[] targetParametersTypes = GetPropertySetParametersTypes(proxyTypeBuilder, targetProperty, true).ToArray(); Type[] targetParametersTypes = GetPropertySetParametersTypes(proxyTypeBuilder, targetProperty, true).ToArray();
@ -197,27 +237,29 @@ public static partial class DuckType
else if (proxyMember is FieldInfo proxyField) else if (proxyMember is FieldInfo proxyField)
{ {
proxyMemberName = proxyField.Name; proxyMemberName = proxyField.Name;
proxyParameterTypes = new Type[] { proxyField.FieldType }; proxyParameterTypes = new[] { proxyField.FieldType };
if (proxyParameterTypes.Length != targetParametersTypes.Length) if (proxyParameterTypes.Length != targetParametersTypes.Length)
{ {
DuckTypePropertyArgumentsLengthException.Throw(targetProperty); DuckTypePropertyArgumentsLengthException.Throw(targetProperty);
} }
} }
MethodBuilder proxyMethod = proxyTypeBuilder.DefineMethod( MethodBuilder proxyMethod = proxyTypeBuilder?.DefineMethod(
"set_" + proxyMemberName, "set_" + proxyMemberName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual,
typeof(void), typeof(void),
proxyParameterTypes); proxyParameterTypes);
LazyILGenerator il = new LazyILGenerator(proxyMethod.GetILGenerator()); LazyILGenerator il = new LazyILGenerator(proxyMethod?.GetILGenerator());
MethodInfo targetMethod = targetProperty.SetMethod;
// Load the instance if needed // Load the instance if needed
if (!targetMethod.IsStatic) if (!targetMethod.IsStatic)
{ {
il.Emit(OpCodes.Ldarg_0); 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 // Load the indexer keys and set value to the stack
@ -227,16 +269,15 @@ public static partial class DuckType
Type targetParamType = targetParametersTypes[pIndex]; Type targetParamType = targetParametersTypes[pIndex];
// Check if the type can be converted of if we need to enable duck chaining // 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 // Load the argument and cast it as Duck type
il.WriteLoadArgument(pIndex, false); il.WriteLoadArgument(pIndex, false);
il.Emit(OpCodes.Castclass, typeof(IDuckType));
// Call IDuckType.Instance property to get the actual value // If this is a forward duck type, we need to cast to IDuckType and extract the original instance
il.EmitCall(OpCodes.Callvirt, DuckTypeInstancePropertyInfo.GetMethod, null); // 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 = typeof(object); targetParamType = duckCastOuterToInner(il, targetParamType, proxyParamType);
} }
else else
{ {
@ -258,7 +299,7 @@ public static partial class DuckType
if (targetMethod.IsPublic) if (targetMethod.IsPublic)
{ {
// We can emit a normal call if we have a public instance with a public property method. // 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 else
{ {
@ -266,7 +307,7 @@ public static partial class DuckType
il.WriteMethodCalli(targetMethod); 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 // 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). // 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.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.Emit(OpCodes.Ret);
dynIL.Flush(); dynIL.Flush();
// Create and load delegate for the DynamicMethod // Create and load delegate for the DynamicMethod
il.WriteDynamicMethodCall(dynMethod, proxyTypeBuilder); 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.Emit(OpCodes.Ret);
il.Flush(); il.Flush();
_methodBuilderGetToken.Invoke(proxyMethod, null); if (proxyMethod is not null)
{
MethodBuilderGetToken.Invoke(proxyMethod, null);
}
return proxyMethod; return proxyMethod;
} }

View File

@ -20,6 +20,8 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.CompilerServices;
// ReSharper disable InconsistentNaming
namespace OpenTelemetry.AutoInstrumentation.DuckTyping; namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
@ -28,43 +30,123 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// </summary> /// </summary>
public static partial class DuckType 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> /// <summary>
/// Gets the Type.GetTypeFromHandle method info /// Gets the Type.GetTypeFromHandle method info
/// </summary> /// </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> /// <summary>
/// Gets the Enum.ToObject method info /// Gets the Enum.ToObject method info
/// </summary> /// </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)] return _enumToObjectMethodInfo;
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>>();
internal static long AssemblyCount => _assemblyCount; internal static long AssemblyCount => _assemblyCount;
internal static long TypeCount => _typeCount; 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> /// <summary>
/// Gets the ModuleBuilder instance from a target type. (.NET Framework / Non AssemblyLoadContext version) /// Gets the ModuleBuilder instance from a target type. (.NET Framework / Non AssemblyLoadContext version)
/// </summary> /// </summary>
@ -73,14 +155,14 @@ public static partial class DuckType
/// <returns>ModuleBuilder instance</returns> /// <returns>ModuleBuilder instance</returns>
private static ModuleBuilder GetModuleBuilder(Type targetType, bool isVisible) private static ModuleBuilder GetModuleBuilder(Type targetType, bool isVisible)
{ {
Assembly targetAssembly = targetType.Assembly ?? typeof(DuckType).Assembly; Assembly targetAssembly = targetType.Assembly;
if (!isVisible) if (!isVisible)
{ {
// If the target type is not visible then we create a new module builder. // If the target type is not visible then we create a new module builder.
// This is the only way to IgnoresAccessChecksToAttribute to work. // This is the only way to IgnoresAccessChecksToAttribute to work.
// We can't reuse the module builder if the attributes collection changes. // 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) if (targetType.IsGenericType)
@ -89,14 +171,14 @@ public static partial class DuckType
{ {
if (type.Assembly != targetAssembly) if (type.Assembly != targetAssembly)
{ {
return CreateModuleBuilder($"DuckTypeGenericTypeAssembly.{targetType.Name}", targetAssembly); return CreateModuleBuilder(DuckTypeConstants.DuckTypeGenericTypeAssemblyPrefix + targetType.Name, targetAssembly);
} }
} }
} }
if (!ActiveBuilders.TryGetValue(targetAssembly, out var moduleBuilder)) 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); ActiveBuilders.Add(targetAssembly, moduleBuilder);
} }
@ -126,6 +208,11 @@ public static partial class DuckType
/// <returns>TProxyDelegate instance</returns> /// <returns>TProxyDelegate instance</returns>
public static TProxyDelegate GetDelegate() 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; return _delegate;
} }

View File

@ -52,7 +52,7 @@ public static partial class DuckType
/// <param name="type">Type to gain internals visibility</param> /// <param name="type">Type to gain internals visibility</param>
private static void EnsureTypeVisibility(ModuleBuilder builder, Type type) 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) if (type.IsGenericType && !type.IsGenericTypeDefinition)
{ {
@ -60,7 +60,7 @@ public static partial class DuckType
{ {
if (!t.IsVisible) 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) 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. // 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) 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>(); hashSet = new HashSet<string>();
_ignoresAccessChecksToAssembliesSetDictionary[builder] = hashSet; IgnoresAccessChecksToAssembliesSetDictionary[builder] = hashSet;
} }
if (hashSet.Add(assemblyName)) 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: // The condition to apply duck chaining is:
// 1. Is a struct with the DuckCopy attribute // 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 // 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) // 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 // 6. The proxy type can't be a CLR type
return proxyType.GetCustomAttribute<DuckCopyAttribute>() != null || return proxyType.GetCustomAttribute<DuckCopyAttribute>() != null ||
(proxyType != targetType && (proxyType != targetType &&
@ -112,14 +119,14 @@ public static partial class DuckType
} }
/// <summary> /// <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> /// </summary>
/// <param name="builder">Module builder</param> /// <param name="builder">Module builder</param>
/// <param name="targetType">Target type</param> /// <param name="targetType">Target type</param>
/// <returns>true for direct method; otherwise, false.</returns> /// <returns>true for direct method; otherwise, false.</returns>
private static bool UseDirectAccessTo(ModuleBuilder builder, Type targetType) private static bool UseDirectAccessTo(ModuleBuilder builder, Type targetType)
{ {
if (builder == null) if (builder is null)
{ {
return targetType.IsPublic || targetType.IsNestedPublic; return targetType.IsPublic || targetType.IsNestedPublic;
} }
@ -129,23 +136,18 @@ public static partial class DuckType
} }
/// <summary> /// <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> /// </summary>
/// <param name="builder">Type builder</param> /// <param name="builder">Type builder</param>
/// <param name="targetType">Target type</param> /// <param name="targetType">Target type</param>
/// <returns>true for direct method; otherwise, false.</returns> /// <returns>true for direct method; otherwise, false.</returns>
private static bool UseDirectAccessTo(TypeBuilder builder, Type targetType) private static bool UseDirectAccessTo(TypeBuilder builder, Type targetType)
{ {
return UseDirectAccessTo((ModuleBuilder)builder?.Module, targetType); if (builder is null)
} {
return true;
}
/// <summary> return UseDirectAccessTo((ModuleBuilder)builder.Module, targetType);
/// 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);
} }
} }

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> // </copyright>
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection; using System.Reflection;
#pragma warning disable SA1649 // File name must match first type name #pragma warning disable SA1649 // File name must match first type name
#pragma warning disable SA1402 // File may only contain a single class #pragma warning disable SA1402 // File may only contain a single class
@ -26,18 +28,37 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// DuckType Exception /// DuckType Exception
/// </summary> /// </summary>
public class DuckTypeException : Exception internal class DuckTypeException : Exception
{ {
internal DuckTypeException(string message) protected DuckTypeException(string message)
: base(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> /// <summary>
/// DuckType proxy type definition is null /// DuckType proxy type definition is null
/// </summary> /// </summary>
public class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException internal class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
{ {
private DuckTypeProxyTypeDefinitionIsNull() private DuckTypeProxyTypeDefinitionIsNull()
: base($"The proxy type definition is null.") : base($"The proxy type definition is null.")
@ -45,6 +66,7 @@ public class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw() internal static void Throw()
{ {
throw new DuckTypeProxyTypeDefinitionIsNull(); throw new DuckTypeProxyTypeDefinitionIsNull();
@ -54,7 +76,7 @@ public class DuckTypeProxyTypeDefinitionIsNull : DuckTypeException
/// <summary> /// <summary>
/// DuckType target object instance is null /// DuckType target object instance is null
/// </summary> /// </summary>
public class DuckTypeTargetObjectInstanceIsNull : DuckTypeException internal class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
{ {
private DuckTypeTargetObjectInstanceIsNull() private DuckTypeTargetObjectInstanceIsNull()
: base($"The target object instance is null.") : base($"The target object instance is null.")
@ -62,6 +84,7 @@ public class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw() internal static void Throw()
{ {
throw new DuckTypeTargetObjectInstanceIsNull(); throw new DuckTypeTargetObjectInstanceIsNull();
@ -71,7 +94,7 @@ public class DuckTypeTargetObjectInstanceIsNull : DuckTypeException
/// <summary> /// <summary>
/// DuckType invalid type conversion exception /// DuckType invalid type conversion exception
/// </summary> /// </summary>
public class DuckTypeInvalidTypeConversionException : DuckTypeException internal class DuckTypeInvalidTypeConversionException : DuckTypeException
{ {
private DuckTypeInvalidTypeConversionException(Type actualType, Type expectedType) private DuckTypeInvalidTypeConversionException(Type actualType, Type expectedType)
: base($"Invalid type conversion from {actualType.FullName} to {expectedType.FullName}") : base($"Invalid type conversion from {actualType.FullName} to {expectedType.FullName}")
@ -79,6 +102,7 @@ public class DuckTypeInvalidTypeConversionException : DuckTypeException
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(Type actualType, Type expectedType) internal static void Throw(Type actualType, Type expectedType)
{ {
throw new DuckTypeInvalidTypeConversionException(actualType, expectedType); throw new DuckTypeInvalidTypeConversionException(actualType, expectedType);
@ -88,7 +112,7 @@ public class DuckTypeInvalidTypeConversionException : DuckTypeException
/// <summary> /// <summary>
/// DuckType property can't be read /// DuckType property can't be read
/// </summary> /// </summary>
public class DuckTypePropertyCantBeReadException : DuckTypeException internal class DuckTypePropertyCantBeReadException : DuckTypeException
{ {
private DuckTypePropertyCantBeReadException(PropertyInfo property) 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.") : 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] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property) internal static void Throw(PropertyInfo property)
{ {
throw new DuckTypePropertyCantBeReadException(property); throw new DuckTypePropertyCantBeReadException(property);
@ -105,7 +130,7 @@ public class DuckTypePropertyCantBeReadException : DuckTypeException
/// <summary> /// <summary>
/// DuckType property can't be written /// DuckType property can't be written
/// </summary> /// </summary>
public class DuckTypePropertyCantBeWrittenException : DuckTypeException internal class DuckTypePropertyCantBeWrittenException : DuckTypeException
{ {
private DuckTypePropertyCantBeWrittenException(PropertyInfo property) 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.") : 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] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property) internal static void Throw(PropertyInfo property)
{ {
throw new DuckTypePropertyCantBeWrittenException(property); throw new DuckTypePropertyCantBeWrittenException(property);
@ -122,7 +148,7 @@ public class DuckTypePropertyCantBeWrittenException : DuckTypeException
/// <summary> /// <summary>
/// DuckType property argument doesn't have the same argument length /// DuckType property argument doesn't have the same argument length
/// </summary> /// </summary>
public class DuckTypePropertyArgumentsLengthException : DuckTypeException internal class DuckTypePropertyArgumentsLengthException : DuckTypeException
{ {
private DuckTypePropertyArgumentsLengthException(PropertyInfo property) private DuckTypePropertyArgumentsLengthException(PropertyInfo property)
: base($"The property '{property.Name}' doesn't have the same number of arguments as the original 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] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(PropertyInfo property) internal static void Throw(PropertyInfo property)
{ {
throw new DuckTypePropertyArgumentsLengthException(property); throw new DuckTypePropertyArgumentsLengthException(property);
@ -139,7 +166,7 @@ public class DuckTypePropertyArgumentsLengthException : DuckTypeException
/// <summary> /// <summary>
/// DuckType field is readonly /// DuckType field is readonly
/// </summary> /// </summary>
public class DuckTypeFieldIsReadonlyException : DuckTypeException internal class DuckTypeFieldIsReadonlyException : DuckTypeException
{ {
private DuckTypeFieldIsReadonlyException(FieldInfo field) 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.") : 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] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(FieldInfo field) internal static void Throw(FieldInfo field)
{ {
throw new DuckTypeFieldIsReadonlyException(field); throw new DuckTypeFieldIsReadonlyException(field);
@ -156,41 +184,25 @@ public class DuckTypeFieldIsReadonlyException : DuckTypeException
/// <summary> /// <summary>
/// DuckType property or field not found /// DuckType property or field not found
/// </summary> /// </summary>
public class DuckTypePropertyOrFieldNotFoundException : DuckTypeException internal class DuckTypePropertyOrFieldNotFoundException : DuckTypeException
{ {
private DuckTypePropertyOrFieldNotFoundException(string name, string duckAttributeName) 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.") : base($"The property or field '{duckAttributeName}' for the proxy property '{name}' was not found in the instance of type '{type}'.")
{ {
} }
[DebuggerHidden] [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); throw new DuckTypePropertyOrFieldNotFoundException(name, duckAttributeName, type?.FullName ?? type?.Name ?? "NULL");
}
}
/// <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);
} }
} }
/// <summary> /// <summary>
/// DuckType struct members cannot be changed exception /// DuckType struct members cannot be changed exception
/// </summary> /// </summary>
public class DuckTypeStructMembersCannotBeChangedException : DuckTypeException internal class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
{ {
private DuckTypeStructMembersCannotBeChangedException(Type type) private DuckTypeStructMembersCannotBeChangedException(Type type)
: base($"Modifying struct members is not supported. [{type.FullName}]") : base($"Modifying struct members is not supported. [{type.FullName}]")
@ -198,6 +210,7 @@ public class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(Type type) internal static void Throw(Type type)
{ {
throw new DuckTypeStructMembersCannotBeChangedException(type); throw new DuckTypeStructMembersCannotBeChangedException(type);
@ -207,7 +220,7 @@ public class DuckTypeStructMembersCannotBeChangedException : DuckTypeException
/// <summary> /// <summary>
/// DuckType target method can not be found exception /// DuckType target method can not be found exception
/// </summary> /// </summary>
public class DuckTypeTargetMethodNotFoundException : DuckTypeException internal class DuckTypeTargetMethodNotFoundException : DuckTypeException
{ {
private DuckTypeTargetMethodNotFoundException(MethodInfo method) private DuckTypeTargetMethodNotFoundException(MethodInfo method)
: base($"The target method for the proxy method '{method}' was not found.") : base($"The target method for the proxy method '{method}' was not found.")
@ -215,6 +228,7 @@ public class DuckTypeTargetMethodNotFoundException : DuckTypeException
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo method) internal static void Throw(MethodInfo method)
{ {
throw new DuckTypeTargetMethodNotFoundException(method); throw new DuckTypeTargetMethodNotFoundException(method);
@ -224,7 +238,7 @@ public class DuckTypeTargetMethodNotFoundException : DuckTypeException
/// <summary> /// <summary>
/// DuckType proxy method parameter is missing exception /// DuckType proxy method parameter is missing exception
/// </summary> /// </summary>
public class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException internal class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException
{ {
private DuckTypeProxyMethodParameterIsMissingException(MethodInfo proxyMethod, ParameterInfo targetParameterInfo) private DuckTypeProxyMethodParameterIsMissingException(MethodInfo proxyMethod, ParameterInfo targetParameterInfo)
: base($"The proxy method '{proxyMethod.Name}' is missing parameter '{targetParameterInfo.Name}' declared in the target method.") : 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] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, ParameterInfo targetParameterInfo) internal static void Throw(MethodInfo proxyMethod, ParameterInfo targetParameterInfo)
{ {
throw new DuckTypeProxyMethodParameterIsMissingException(proxyMethod, targetParameterInfo); throw new DuckTypeProxyMethodParameterIsMissingException(proxyMethod, targetParameterInfo);
@ -241,7 +256,7 @@ public class DuckTypeProxyMethodParameterIsMissingException : DuckTypeException
/// <summary> /// <summary>
/// DuckType parameter signature mismatch between proxy and target method /// DuckType parameter signature mismatch between proxy and target method
/// </summary> /// </summary>
public class DuckTypeProxyAndTargetMethodParameterSignatureMismatchException : DuckTypeException internal class DuckTypeProxyAndTargetMethodParameterSignatureMismatchException : DuckTypeException
{ {
private DuckTypeProxyAndTargetMethodParameterSignatureMismatchException(MethodInfo proxyMethod, MethodInfo targetMethod) private DuckTypeProxyAndTargetMethodParameterSignatureMismatchException(MethodInfo proxyMethod, MethodInfo targetMethod)
: base($"Parameter signature mismatch between proxy '{proxyMethod}' and target method '{targetMethod}'") : base($"Parameter signature mismatch between proxy '{proxyMethod}' and target method '{targetMethod}'")
@ -249,16 +264,35 @@ public class DuckTypeProxyAndTargetMethodParameterSignatureMismatchException : D
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod) internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod)
{ {
throw new DuckTypeProxyAndTargetMethodParameterSignatureMismatchException(proxyMethod, 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> /// <summary>
/// DuckType proxy methods with generic parameters are not supported in non public instances exception /// DuckType proxy methods with generic parameters are not supported in non public instances exception
/// </summary> /// </summary>
public class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException : DuckTypeException internal class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException : DuckTypeException
{ {
private DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException(MethodInfo proxyMethod) private DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException(MethodInfo proxyMethod)
: base($"The proxy method with generic parameters '{proxyMethod}' are not supported on non public instances") : base($"The proxy method with generic parameters '{proxyMethod}' are not supported on non public instances")
@ -266,6 +300,7 @@ public class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicIns
} }
[DebuggerHidden] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod) internal static void Throw(MethodInfo proxyMethod)
{ {
throw new DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException(proxyMethod); throw new DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicInstancesException(proxyMethod);
@ -275,7 +310,7 @@ public class DuckTypeProxyMethodsWithGenericParametersNotSupportedInNonPublicIns
/// <summary> /// <summary>
/// DuckType proxy method has an ambiguous match in the target type exception /// DuckType proxy method has an ambiguous match in the target type exception
/// </summary> /// </summary>
public class DuckTypeTargetMethodAmbiguousMatchException : DuckTypeException internal class DuckTypeTargetMethodAmbiguousMatchException : DuckTypeException
{ {
private DuckTypeTargetMethodAmbiguousMatchException(MethodInfo proxyMethod, MethodInfo targetMethod, MethodInfo targetMethod2) 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}'") : 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] [DebuggerHidden]
[DoesNotReturn]
internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod, MethodInfo targetMethod2) internal static void Throw(MethodInfo proxyMethod, MethodInfo targetMethod, MethodInfo targetMethod2)
{ {
throw new DuckTypeTargetMethodAmbiguousMatchException(proxyMethod, targetMethod, 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> // </copyright>
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping; namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
@ -22,7 +23,7 @@ namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// Duck type extensions /// Duck type extensions
/// </summary> /// </summary>
public static class DuckTypeExtensions internal static class DuckTypeExtensions
{ {
/// <summary> /// <summary>
/// Gets the duck type instance for the object implementing a base class or interface T /// 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(); 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()); value = proxyResult.CreateInstance<T>(instance)!;
if (proxyResult.Success) return true;
{
value = proxyResult.CreateInstance<T>(instance);
return true;
}
} }
value = default; value = default;
@ -88,7 +86,7 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw(); DuckTypeTargetObjectInstanceIsNull.Throw();
} }
if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic)) if (targetType != null)
{ {
DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType()); DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
if (proxyResult.Success) if (proxyResult.Success)
@ -117,13 +115,10 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw(); 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()); return proxyResult.CreateInstance<T>(instance);
if (proxyResult.Success)
{
return proxyResult.CreateInstance<T>(instance);
}
} }
return null; return null;
@ -143,7 +138,7 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw(); DuckTypeTargetObjectInstanceIsNull.Throw();
} }
if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic)) if (targetType != null)
{ {
DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType()); DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
if (proxyResult.Success) if (proxyResult.Success)
@ -169,12 +164,7 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw(); DuckTypeTargetObjectInstanceIsNull.Throw();
} }
if (DuckType.CreateCache<T>.IsVisible) return DuckType.CanCreate<T>(instance);
{
return DuckType.CanCreate<T>(instance);
}
return false;
} }
/// <summary> /// <summary>
@ -191,11 +181,53 @@ public static class DuckTypeExtensions
DuckTypeTargetObjectInstanceIsNull.Throw(); DuckTypeTargetObjectInstanceIsNull.Throw();
} }
if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic)) if (targetType != null)
{ {
return DuckType.CanCreate(targetType, instance); return DuckType.CanCreate(targetType, instance);
} }
return false; 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> // </copyright>
using System; using System;
using System.ComponentModel;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping; namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// Duck type interface /// Duck type interface
/// </summary> /// </summary>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IDuckType public interface IDuckType
{ {
/// <summary> /// <summary>
@ -32,4 +35,10 @@ public interface IDuckType
/// Gets instance Type /// Gets instance Type
/// </summary> /// </summary>
Type Type { get; } 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> /// <summary>
/// Internal IL Helpers /// Internal IL Helpers
/// </summary> /// </summary>
// ReSharper disable once InconsistentNaming
internal static class ILHelpersExtensions 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) 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); methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
delType = delegateType.CreateTypeInfo().AsType(); var delegateTypeInfo = delegateType.CreateTypeInfo();
invokeMethod = delType.GetMethod("Invoke"); if (delegateTypeInfo is null)
{
DuckTypeException.Throw($"Error creating the delegate type info for {delegateType.FullName}");
}
delType = delegateTypeInfo.AsType();
invokeMethod = delType.GetMethod("Invoke")!;
} }
/// <summary> /// <summary>
@ -345,11 +352,49 @@ internal static class ILHelpersExtensions
} }
else if (expectedUnderlyingType != typeof(object)) 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); 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> /// <summary>
/// Write a Call to a method using Calli /// Write a Call to a method using Calli
/// </summary> /// </summary>
@ -364,7 +409,7 @@ internal static class ILHelpersExtensions
method.CallingConvention, method.CallingConvention,
method.ReturnType, method.ReturnType,
method.GetParameters().Select(p => p.ParameterType).ToArray(), method.GetParameters().Select(p => p.ParameterType).ToArray(),
null); null!);
} }
/// <summary> /// <summary>
@ -375,25 +420,31 @@ internal static class ILHelpersExtensions
/// <param name="proxyType">ProxyType builder</param> /// <param name="proxyType">ProxyType builder</param>
internal static void WriteDynamicMethodCall(this LazyILGenerator il, DynamicMethod dynamicMethod, TypeBuilder proxyType) 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 // We create a custom delegate inside the module builder
CreateDelegateTypeFor(proxyType, dynamicMethod, out Type delegateType, out MethodInfo invokeMethod); CreateDelegateTypeFor(proxyType, dynamicMethod, out Type delegateType, out MethodInfo invokeMethod);
int index; int index;
lock (_dynamicMethods) lock (DynamicMethods)
{ {
_dynamicMethods.Add(dynamicMethod); DynamicMethods.Add(dynamicMethod);
index = _dynamicMethods.Count - 1; index = DynamicMethods.Count - 1;
} }
// We fill the DelegateCache<> for that custom type with the delegate instance // 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); var delegateCacheType = typeof(DuckType.DelegateCache<>).MakeGenericType(delegateType);
fillDelegateMethodInfo.Invoke(null, new object[] { index }); 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) // 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.SetOffset(0);
il.EmitCall(OpCodes.Call, typeof(DuckType.DelegateCache<>).MakeGenericType(delegateType).GetMethod("GetDelegate"), null); il.EmitCall(OpCodes.Call, delegateCacheType.GetMethod("GetDelegate")!, null!);
il.ResetOffset(); il.ResetOffset();
// We emit the call to the delegate invoke method. // 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. // limitations under the License.
// </copyright> // </copyright>
using System; // ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices;
namespace OpenTelemetry.AutoInstrumentation.DuckTyping;
/// <summary> /// <summary>
/// This attribute is recognized by the CLR and allow us to disable visibility checks for certain assemblies (only from 4.6+) /// This attribute is recognized by the CLR and allow us to disable visibility checks for certain assemblies (only from 4.6+)
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class IgnoresAccessChecksToAttribute : Attribute internal class IgnoresAccessChecksToAttribute : Attribute
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="IgnoresAccessChecksToAttribute"/> class. /// Initializes a new instance of the <see cref="IgnoresAccessChecksToAttribute"/> class.

View File

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