From 1d406b1a0ad54348dbdda4c9117897921d95f950 Mon Sep 17 00:00:00 2001 From: Avi Avni Date: Tue, 17 Apr 2018 17:14:34 +0300 Subject: [PATCH] Enable generic attributes (#9189) --- .../src/System/Reflection/CustomAttribute.cs | 10 +- src/vm/callhelpers.h | 34 ++++ src/vm/customattribute.cpp | 20 +- src/vm/customattribute.h | 2 +- .../GenericAttribute/GenericAttributeMetadata.cs | 78 +++++++ .../GenericAttribute/GenericAttributeMetadata.il | 223 +++++++++++++++++++++ .../GenericAttributeMetadata.ilproj | 35 ++++ .../GenericAttribute/GenericAttributeTests.cs | 163 +++++++++++++++ .../GenericAttribute/GenericAttributeTests.csproj | 31 +++ 9 files changed, 578 insertions(+), 18 deletions(-) create mode 100644 tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs create mode 100644 tests/src/reflection/GenericAttribute/GenericAttributeMetadata.il create mode 100644 tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj create mode 100644 tests/src/reflection/GenericAttribute/GenericAttributeTests.cs create mode 100644 tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj diff --git a/src/mscorlib/src/System/Reflection/CustomAttribute.cs b/src/mscorlib/src/System/Reflection/CustomAttribute.cs index 745522b..fb102c1 100644 --- a/src/mscorlib/src/System/Reflection/CustomAttribute.cs +++ b/src/mscorlib/src/System/Reflection/CustomAttribute.cs @@ -1535,7 +1535,7 @@ namespace System.Reflection // Create custom attribute object if (ctorHasParameters) { - attribute = CreateCaObject(decoratedModule, ctor, ref blobStart, blobEnd, out cNamedArgs); + attribute = CreateCaObject(decoratedModule, attributeType, ctor, ref blobStart, blobEnd, out cNamedArgs); } else { @@ -1695,7 +1695,7 @@ namespace System.Reflection if (ctorHasParameters) { // Resolve method ctor token found in decorated decoratedModule scope - ctor = ModuleHandle.ResolveMethodHandleInternal(decoratedModule.GetNativeHandle(), caRecord.tkCtor); + ctor = decoratedModule.ResolveMethod(caRecord.tkCtor, attributeType.GenericTypeArguments, null).MethodHandle.GetMethodInfo(); } else { @@ -1826,13 +1826,13 @@ namespace System.Reflection } [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe Object _CreateCaObject(RuntimeModule pModule, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs); - private static unsafe Object CreateCaObject(RuntimeModule module, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs) + private static extern unsafe Object _CreateCaObject(RuntimeModule pModule, RuntimeType type, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs); + private static unsafe Object CreateCaObject(RuntimeModule module, RuntimeType type, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs) { byte* pBlob = (byte*)blob; byte* pBlobEnd = (byte*)blobEnd; int cNamedArgs; - object ca = _CreateCaObject(module, ctor, &pBlob, pBlobEnd, &cNamedArgs); + object ca = _CreateCaObject(module, type, ctor, &pBlob, pBlobEnd, &cNamedArgs); blob = (IntPtr)pBlob; namedArgs = cNamedArgs; return ca; diff --git a/src/vm/callhelpers.h b/src/vm/callhelpers.h index 446105b..a10ad76 100644 --- a/src/vm/callhelpers.h +++ b/src/vm/callhelpers.h @@ -131,6 +131,21 @@ private: m_argIt.ForceSigWalk(); } + void DefaultInit(TypeHandle th) + { + CONTRACTL + { + MODE_ANY; + GC_TRIGGERS; + THROWS; + } + CONTRACTL_END; + + m_pCallTarget = m_pMD->GetCallTarget(NULL, th); + + m_argIt.ForceSigWalk(); +} + #ifdef FEATURE_INTERPRETER public: void CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *pReturnValue, int cbReturnValue, bool transitionToPreemptive = false); @@ -234,6 +249,25 @@ public: DefaultInit(porProtectedThis); } + MethodDescCallSite(MethodDesc* pMD, TypeHandle th) : + m_pMD(pMD), + m_methodSig(pMD, th), + m_argIt(&m_methodSig) + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + // We don't have a "this" pointer - ensure that we have activated the containing module + m_pMD->EnsureActive(); + + DefaultInit(th); + } + // // Only use this constructor if you're certain you know where // you're going and it cannot be affected by generics/virtual diff --git a/src/vm/customattribute.cpp b/src/vm/customattribute.cpp index 6c76541..e77d55a 100644 --- a/src/vm/customattribute.cpp +++ b/src/vm/customattribute.cpp @@ -670,7 +670,7 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC CONTRACTL { FCALL_CHECK; PRECONDITION(CheckPointer(pCaTypeUNSAFE)); - PRECONDITION(!pCaTypeUNSAFE->GetType().IsGenericVariable()); + PRECONDITION(!pCaTypeUNSAFE->GetType().IsGenericVariable()); PRECONDITION(pCaTypeUNSAFE->GetType().IsValueType() || CheckPointer(pCtorUNSAFE)); } CONTRACTL_END; @@ -694,10 +694,6 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC PRECONDITION( (!pCtor && gc.refCaType->GetType().IsValueType() && !gc.refCaType->GetType().GetMethodTable()->HasDefaultConstructor()) || (pCtor == gc.refCaType->GetType().GetMethodTable()->GetDefaultConstructor())); - - // If we relax this, we need to insure custom attributes construct properly for Nullable - if (gc.refCaType->GetType().HasInstantiation()) - COMPlusThrow(kNotSupportedException, W("Argument_GenericsInvalid")); gc.o = pCaMT->Allocate(); @@ -731,16 +727,20 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC } FCIMPLEND -FCIMPL5(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs) +FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs) { FCALL_CONTRACT; struct { + REFLECTCLASSBASEREF refCaType; OBJECTREF ca; REFLECTMETHODREF refCtor; REFLECTMODULEBASEREF refAttributedModule; } gc; + gc.refCaType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pCaTypeUNSAFE); + TypeHandle th = gc.refCaType->GetType(); + gc.ca = NULL; gc.refCtor = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE); gc.refAttributedModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pAttributedModuleUNSAFE); @@ -749,10 +749,10 @@ FCIMPL5(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); MethodDesc* pCtorMD = gc.refCtor->GetMethod(); - + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); { - MethodDescCallSite ctorCallSite(pCtorMD); + MethodDescCallSite ctorCallSite(pCtorMD, th); MetaSig* pSig = ctorCallSite.GetMetaSig(); BYTE* pBlob = *ppBlob; @@ -767,10 +767,6 @@ FCIMPL5(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF)); memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF)); - // If we relax this, we need to insure custom attributes construct properly for Nullable - if (pCtorMD->GetMethodTable()->HasInstantiation()) - COMPlusThrow(kNotSupportedException, W("Argument_GenericsInvalid")); - // load the this pointer argToProtect[0] = pCtorMD->GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation diff --git a/src/vm/customattribute.h b/src/vm/customattribute.h index d5aa4dd..f2e5ee9 100644 --- a/src/vm/customattribute.h +++ b/src/vm/customattribute.h @@ -172,7 +172,7 @@ public: // custom attributes utility functions static FCDECL5(VOID, ParseAttributeUsageAttribute, PVOID pData, ULONG cData, ULONG* pTargets, CLR_BOOL* pInherited, CLR_BOOL* pAllowMultiple); - static FCDECL5(LPVOID, CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs); + static FCDECL6(LPVOID, CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs); static FCDECL7(void, GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value); static FCDECL4(VOID, GetSecurityAttributes, ReflectModuleBaseObject *pModuleUNSAFE, DWORD tkToken, CLR_BOOL fAssembly, PTRARRAYREF* ppArray); diff --git a/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs new file mode 100644 index 0000000..1c6ce42 --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// + +using System; +using System.Reflection; +using System.Collections; +using System.Runtime.CompilerServices; + +[assembly: SingleAttribute()] +[assembly: SingleAttribute()] + +[assembly: MultiAttribute()] +[assembly: MultiAttribute(1)] +[assembly: MultiAttribute(Value = 2)] +[assembly: MultiAttribute()] +[assembly: MultiAttribute(true)] + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false)] +public class SingleAttribute : Attribute +{ + +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)] +public class MultiAttribute : Attribute +{ + public T Value { get; set; } + + public MultiAttribute() + { + } + + public MultiAttribute(T value) + { + Value = value; + } +} + +public enum MyEnum +{ + Ctor, + Property +} + +[SingleAttribute()] +[SingleAttribute()] +[MultiAttribute()] +[MultiAttribute(1)] +[MultiAttribute(Value = 2)] +[MultiAttribute()] +[MultiAttribute(true)] +[MultiAttribute(Value = true)] +[MultiAttribute()] +[MultiAttribute("Ctor")] +[MultiAttribute(Value = "Property")] +[MultiAttribute(typeof(Class))] +[MultiAttribute(Value = typeof(Class.Derive))] +[MultiAttribute(MyEnum.Ctor)] +[MultiAttribute(Value = MyEnum.Property)] +public class Class +{ + public class Derive : Class + { + + } + + [SingleAttribute()] + [SingleAttribute()] + [MultiAttribute()] + [MultiAttribute(1)] + [MultiAttribute(Value = 2)] + [MultiAttribute()] + [MultiAttribute(true)] + public int Property { get; set; } +} \ No newline at end of file diff --git a/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.il b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.il new file mode 100644 index 0000000..71d5b16 --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.il @@ -0,0 +1,223 @@ + +// Microsoft (R) .NET Framework IL Disassembler. Version 4.5.22220.0 + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib { } +.assembly GenericAttributeMetadata +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) + + .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 08 05 56 61 6C 75 65 02 00 00 00 ) // ....T..Value.... + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 ) + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module GenericAttributeMetadata.dll +// MVID: {97ADA31C-7529-4F22-9907-B16BE1E0AF0B} +.imagebase 0x10000000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x0000025583AE0000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit SingleAttribute`1 + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( 01 00 85 00 00 00 01 00 54 02 0D 41 6C 6C 6F 77 // ........T..Allow + 4D 75 6C 74 69 70 6C 65 00 ) // Multiple. + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method SingleAttribute`1::.ctor + +} // end of class SingleAttribute`1 + +.class public auto ansi beforefieldinit MultiAttribute`1 + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( 01 00 85 00 00 00 01 00 54 02 0D 41 6C 6C 6F 77 // ........T..Allow + 4D 75 6C 74 69 70 6C 65 01 ) // Multiple. + .field private !T 'k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .method public hidebysig specialname instance !T + get_Value() cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld !0 class MultiAttribute`1::'k__BackingField' + IL_0006: ret + } // end of method MultiAttribute`1::get_Value + + .method public hidebysig specialname instance void + set_Value(!T 'value') cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld !0 class MultiAttribute`1::'k__BackingField' + IL_0007: ret + } // end of method MultiAttribute`1::set_Value + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: nop + IL_0007: nop + IL_0008: ret + } // end of method MultiAttribute`1::.ctor + + .method public hidebysig specialname rtspecialname + instance void .ctor(!T 'value') cil managed + { + // Code size 17 (0x11) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: nop + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.1 + IL_000a: call instance void class MultiAttribute`1::set_Value(!0) + IL_000f: nop + IL_0010: ret + } // end of method MultiAttribute`1::.ctor + + .property instance !T Value() + { + .get instance !T MultiAttribute`1::get_Value() + .set instance void MultiAttribute`1::set_Value(!T) + } // end of property MultiAttribute`1::Value +} // end of class MultiAttribute`1 + +.class public auto ansi sealed MyEnum + extends [mscorlib]System.Enum +{ + .field public specialname rtspecialname int32 value__ + .field public static literal valuetype MyEnum Ctor = int32(0x00000000) + .field public static literal valuetype MyEnum Property = int32(0x00000001) +} // end of class MyEnum + +.class public auto ansi beforefieldinit Class + extends [mscorlib]System.Object +{ + .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 08 05 56 61 6C 75 65 02 00 00 00 ) // ....T..Value.... + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 02 05 56 61 6C 75 65 01 ) // ....T..Value. + .custom instance void class MultiAttribute`1>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 04 43 74 6F 72 00 00 ) // ...Ctor.. + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 0E 05 56 61 6C 75 65 08 50 72 6F // ....T..Value.Pro + 70 65 72 74 79 ) // perty + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 05 43 6C 61 73 73 00 00 ) // ...Class.. + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 50 05 56 61 6C 75 65 0C 43 6C 61 // ....TP.Value.Cla + 73 73 2B 44 65 72 69 76 65 ) // ss+Derive + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 55 06 4D 79 45 6E 75 6D 05 56 61 // ....TU.MyEnum.Va + 6C 75 65 01 00 00 00 ) // lue.... + .class auto ansi nested public beforefieldinit Derive + extends Class + { + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void Class::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method Derive::.ctor + + } // end of class Derive + + .field private int32 'k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .method public hidebysig specialname instance int32 + get_Property() cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 Class::'k__BackingField' + IL_0006: ret + } // end of method Class::get_Property + + .method public hidebysig specialname instance void + set_Property(int32 'value') cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld int32 Class::'k__BackingField' + IL_0007: ret + } // end of method Class::set_Property + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method Class::.ctor + + .property instance int32 Property() + { + .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 08 05 56 61 6C 75 65 02 00 00 00 ) // ....T..Value.... + .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 ) + .get instance int32 Class::get_Property() + .set instance void Class::set_Property(int32) + } // end of property Class::Property +} // end of class Class + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file GenericAttributeMetadata.res diff --git a/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj new file mode 100644 index 0000000..36e5496 --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj @@ -0,0 +1,35 @@ + + + + + GenericAttributeMetadata + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + true + Library + BuildOnly + 0 + + + + + False + + + + + + + + + + True + + + + + + + diff --git a/tests/src/reflection/GenericAttribute/GenericAttributeTests.cs b/tests/src/reflection/GenericAttribute/GenericAttributeTests.cs new file mode 100644 index 0000000..762f011 --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeTests.cs @@ -0,0 +1,163 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +class Program +{ + static int Main(string[] args) + { + Assembly assembly = typeof(Class).GetTypeInfo().Assembly; + Assert(CustomAttributeExtensions.GetCustomAttribute>(assembly) != null); + Assert(((ICustomAttributeProvider)assembly).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute>(assembly) != null); + Assert(((ICustomAttributeProvider)assembly).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.IsDefined(assembly, typeof(SingleAttribute))); + Assert(((ICustomAttributeProvider)assembly).IsDefined(typeof(SingleAttribute), true)); + Assert(CustomAttributeExtensions.IsDefined(assembly, typeof(SingleAttribute))); + Assert(((ICustomAttributeProvider)assembly).IsDefined(typeof(SingleAttribute), true)); + + TypeInfo programTypeInfo = typeof(Class).GetTypeInfo(); + Assert(CustomAttributeExtensions.GetCustomAttribute>(programTypeInfo) != null); + Assert(((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute>(programTypeInfo) != null); + Assert(((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.IsDefined(programTypeInfo, typeof(SingleAttribute))); + Assert(((ICustomAttributeProvider)programTypeInfo).IsDefined(typeof(SingleAttribute), true)); + Assert(CustomAttributeExtensions.IsDefined(programTypeInfo, typeof(SingleAttribute))); + Assert(((ICustomAttributeProvider)programTypeInfo).IsDefined(typeof(SingleAttribute), true)); + + var propertyPropertyInfo = typeof(Class).GetTypeInfo().GetProperty(nameof(Class.Property)); + Assert(CustomAttributeExtensions.GetCustomAttribute>(propertyPropertyInfo) != null); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute>(propertyPropertyInfo) != null); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.IsDefined(propertyPropertyInfo, typeof(SingleAttribute))); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).IsDefined(typeof(SingleAttribute), true)); + Assert(CustomAttributeExtensions.IsDefined(propertyPropertyInfo, typeof(SingleAttribute))); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).IsDefined(typeof(SingleAttribute), true)); + + var deriveTypeInfo = typeof(Class.Derive).GetTypeInfo(); + Assert(CustomAttributeExtensions.GetCustomAttribute>(deriveTypeInfo, false) == null); + Assert(((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute>(deriveTypeInfo, false) == null); + Assert(((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); + Assert(!CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute), false)); + Assert(!CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute), false)); + + Assert(CustomAttributeExtensions.GetCustomAttribute>(deriveTypeInfo, true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute>(deriveTypeInfo, true) != null); + Assert(CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute), true)); + Assert(((ICustomAttributeProvider)deriveTypeInfo).IsDefined(typeof(SingleAttribute), true)); + Assert(CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute), true)); + Assert(((ICustomAttributeProvider)deriveTypeInfo).IsDefined(typeof(SingleAttribute), true)); + + var a1 = CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, true); + AssertAny(a1, a => a is SingleAttribute); + AssertAny(a1, a => a is SingleAttribute); + AssertAny(a1, a => (a as MultiAttribute)?.Value == 0); + AssertAny(a1, a => (a as MultiAttribute)?.Value == 1); + AssertAny(a1, a => (a as MultiAttribute)?.Value == 2); + AssertAny(a1, a => (a as MultiAttribute)?.Value == false); + AssertAny(a1, a => (a as MultiAttribute)?.Value == true, 2); + AssertAny(a1, a => (a as MultiAttribute)?.Value == null); + + var b1 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(true); + AssertAny(b1, a => a is SingleAttribute); + AssertAny(b1, a => a is SingleAttribute); + AssertAny(b1, a => (a as MultiAttribute)?.Value == 0); + AssertAny(b1, a => (a as MultiAttribute)?.Value == 1); + AssertAny(b1, a => (a as MultiAttribute)?.Value == 2); + AssertAny(b1, a => (a as MultiAttribute)?.Value == false); + AssertAny(b1, a => (a as MultiAttribute)?.Value == true, 2); + AssertAny(b1, a => (a as MultiAttribute)?.Value == null); + + var a2 = CustomAttributeExtensions.GetCustomAttributes(deriveTypeInfo, false); + Assert(!a2.GetEnumerator().MoveNext()); + + var b2 = ((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(false); + Assert(!b2.GetEnumerator().MoveNext()); + + var a3 = CustomAttributeExtensions.GetCustomAttributes(deriveTypeInfo, true); + AssertAny(a3, a => a is SingleAttribute); + AssertAny(a3, a => a is SingleAttribute); + AssertAny(a3, a => (a as MultiAttribute)?.Value == 0); + AssertAny(a3, a => (a as MultiAttribute)?.Value == 1); + AssertAny(a3, a => (a as MultiAttribute)?.Value == 2); + AssertAny(a3, a => (a as MultiAttribute)?.Value == false); + AssertAny(a3, a => (a as MultiAttribute)?.Value == true); + + var b3 = ((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(true); + AssertAny(b3, a => a is SingleAttribute); + AssertAny(b3, a => a is SingleAttribute); + AssertAny(b3, a => (a as MultiAttribute)?.Value == 0); + AssertAny(b3, a => (a as MultiAttribute)?.Value == 1); + AssertAny(b3, a => (a as MultiAttribute)?.Value == 2); + AssertAny(b3, a => (a as MultiAttribute)?.Value == false); + AssertAny(b3, a => (a as MultiAttribute)?.Value == true); + + var a4 = CustomAttributeExtensions.GetCustomAttributes>(programTypeInfo, true); + AssertAny(a4, a => a is SingleAttribute); + + var b4 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true); + AssertAny(b4, a => a is SingleAttribute); + + var a5 = CustomAttributeExtensions.GetCustomAttributes>(programTypeInfo); + AssertAny(a5, a => a is SingleAttribute); + + var b5 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true); + AssertAny(b5, a => a is SingleAttribute); + + var a6 = CustomAttributeExtensions.GetCustomAttributes>(programTypeInfo, true); + AssertAny(a6, a => (a as MultiAttribute)?.Value == 0); + AssertAny(a6, a => (a as MultiAttribute)?.Value == 1); + AssertAny(a6, a => (a as MultiAttribute)?.Value == 2); + + var b6 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute), true); + AssertAny(b6, a => (a as MultiAttribute)?.Value == 0); + AssertAny(b6, a => (a as MultiAttribute)?.Value == 1); + AssertAny(b6, a => (a as MultiAttribute)?.Value == 2); + + var a7 = CustomAttributeExtensions.GetCustomAttributes>(programTypeInfo, true); + AssertAny(a7, a => (a as MultiAttribute)?.Value == false); + AssertAny(a7, a => (a as MultiAttribute)?.Value == true); + + var b7 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute), true); + AssertAny(b7, a => (a as MultiAttribute)?.Value == false); + AssertAny(b7, a => (a as MultiAttribute)?.Value == true); + + var a8 = CustomAttributeExtensions.GetCustomAttributes>(programTypeInfo, true); + AssertAny(a8, a => (a as MultiAttribute)?.Value == null); + + var b8 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute), true); + AssertAny(b8, a => (a as MultiAttribute)?.Value == null); + + Assert(CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, typeof(MultiAttribute<>), false) == null); + Assert(CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, typeof(MultiAttribute<>), true) == null); + Assert(!((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute<>), true).GetEnumerator().MoveNext()); + + return 100; + } + + static void Assert(bool condition, [CallerLineNumberAttribute]int line = 0) + { + if(!condition) + { + throw new Exception($"Error in line: {line}"); + } + } + + static void AssertAny(IEnumerable source, Func condition, int count = 1, [CallerLineNumberAttribute]int line = 0) + { + var enumerator = source.GetEnumerator(); + while (enumerator.MoveNext()) + { + if(condition(enumerator.Current as Attribute) && --count == 0) + { + return; + } + } + throw new Exception($"Error in line: {line}"); + } +} diff --git a/tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj b/tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj new file mode 100644 index 0000000..3737ee9 --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj @@ -0,0 +1,31 @@ + + + + + GenericAttributeTests + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + true + Exe + BuildAndRun + 1 + + + + False + + + + + + + + + + + + + \ No newline at end of file -- 2.7.4