diff options
author | Avi Avni <avi.avni@gmail.com> | 2018-04-17 17:14:34 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2018-04-17 07:14:34 -0700 |
commit | 1d406b1a0ad54348dbdda4c9117897921d95f950 (patch) | |
tree | c76cd400804ccee62a5565626b27427fd3609be8 | |
parent | bcfb0c959bbac65110c22b695e73249b8dddbd18 (diff) | |
download | coreclr-1d406b1a0ad54348dbdda4c9117897921d95f950.tar.gz coreclr-1d406b1a0ad54348dbdda4c9117897921d95f950.tar.bz2 coreclr-1d406b1a0ad54348dbdda4c9117897921d95f950.zip |
Enable generic attributes (#9189)
-rw-r--r-- | src/mscorlib/src/System/Reflection/CustomAttribute.cs | 10 | ||||
-rw-r--r-- | src/vm/callhelpers.h | 34 | ||||
-rw-r--r-- | src/vm/customattribute.cpp | 20 | ||||
-rw-r--r-- | src/vm/customattribute.h | 2 | ||||
-rw-r--r-- | tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs | 78 | ||||
-rw-r--r-- | tests/src/reflection/GenericAttribute/GenericAttributeMetadata.il | 223 | ||||
-rw-r--r-- | tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj | 35 | ||||
-rw-r--r-- | tests/src/reflection/GenericAttribute/GenericAttributeTests.cs | 163 | ||||
-rw-r--r-- | tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj | 31 |
9 files changed, 578 insertions, 18 deletions
diff --git a/src/mscorlib/src/System/Reflection/CustomAttribute.cs b/src/mscorlib/src/System/Reflection/CustomAttribute.cs index 745522b0b1..fb102c128d 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 446105bfba..a10ad765be 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 6c765414c3..e77d55a498 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<T> - 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<T> - 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 d5aa4dd06f..f2e5ee9c1b 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 0000000000..1c6ce4207b --- /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<int>()] +[assembly: SingleAttribute<bool>()] + +[assembly: MultiAttribute<int>()] +[assembly: MultiAttribute<int>(1)] +[assembly: MultiAttribute<int>(Value = 2)] +[assembly: MultiAttribute<bool>()] +[assembly: MultiAttribute<bool>(true)] + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false)] +public class SingleAttribute<T> : Attribute +{ + +} + +[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)] +public class MultiAttribute<T> : Attribute +{ + public T Value { get; set; } + + public MultiAttribute() + { + } + + public MultiAttribute(T value) + { + Value = value; + } +} + +public enum MyEnum +{ + Ctor, + Property +} + +[SingleAttribute<int>()] +[SingleAttribute<bool>()] +[MultiAttribute<int>()] +[MultiAttribute<int>(1)] +[MultiAttribute<int>(Value = 2)] +[MultiAttribute<bool>()] +[MultiAttribute<bool>(true)] +[MultiAttribute<bool>(Value = true)] +[MultiAttribute<bool?>()] +[MultiAttribute<string>("Ctor")] +[MultiAttribute<string>(Value = "Property")] +[MultiAttribute<Type>(typeof(Class))] +[MultiAttribute<Type>(Value = typeof(Class.Derive))] +[MultiAttribute<MyEnum>(MyEnum.Ctor)] +[MultiAttribute<MyEnum>(Value = MyEnum.Property)] +public class Class +{ + public class Derive : Class + { + + } + + [SingleAttribute<int>()] + [SingleAttribute<bool>()] + [MultiAttribute<int>()] + [MultiAttribute<int>(1)] + [MultiAttribute<int>(Value = 2)] + [MultiAttribute<bool>()] + [MultiAttribute<bool>(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 0000000000..71d5b16d0b --- /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<int32>::.ctor() = ( 01 00 00 00 ) + .custom instance void class SingleAttribute`1<bool>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.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<bool>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<bool>::.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<T> + 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<T> + 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 '<Value>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<!T>::'<Value>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<!T>::'<Value>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<!T>::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<int32>::.ctor() = ( 01 00 00 00 ) + .custom instance void class SingleAttribute`1<bool>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.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<bool>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<bool>::.ctor(!0) = ( 01 00 01 00 00 ) + .custom instance void class MultiAttribute`1<bool>::.ctor() = ( 01 00 01 00 54 02 05 56 61 6C 75 65 01 ) // ....T..Value. + .custom instance void class MultiAttribute`1<valuetype [mscorlib]System.Nullable`1<bool>>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<string>::.ctor(!0) = ( 01 00 04 43 74 6F 72 00 00 ) // ...Ctor.. + .custom instance void class MultiAttribute`1<string>::.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<class [mscorlib]System.Type>::.ctor(!0) = ( 01 00 05 43 6C 61 73 73 00 00 ) // ...Class.. + .custom instance void class MultiAttribute`1<class [mscorlib]System.Type>::.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<valuetype MyEnum>::.ctor(!0) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1<valuetype MyEnum>::.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 '<Property>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::'<Property>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::'<Property>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<int32>::.ctor() = ( 01 00 00 00 ) + .custom instance void class SingleAttribute`1<bool>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) + .custom instance void class MultiAttribute`1<int32>::.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<bool>::.ctor() = ( 01 00 00 00 ) + .custom instance void class MultiAttribute`1<bool>::.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 0000000000..36e54965a1 --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>GenericAttributeMetadata</AssemblyName> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <OutputType>Library</OutputType> + <CLRTestKind>BuildOnly</CLRTestKind> + <CLRTestPriority>0</CLRTestPriority> + </PropertyGroup> + + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + + <ItemGroup> + <Compile Include="GenericAttributeMetadata.il" /> + </ItemGroup> + + + <PropertyGroup> + <Optimize>True</Optimize> + </PropertyGroup> + + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/reflection/GenericAttribute/GenericAttributeTests.cs b/tests/src/reflection/GenericAttribute/GenericAttributeTests.cs new file mode 100644 index 0000000000..762f011fae --- /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<SingleAttribute<int>>(assembly) != null); + Assert(((ICustomAttributeProvider)assembly).GetCustomAttributes(typeof(SingleAttribute<int>), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<bool>>(assembly) != null); + Assert(((ICustomAttributeProvider)assembly).GetCustomAttributes(typeof(SingleAttribute<bool>), true) != null); + Assert(CustomAttributeExtensions.IsDefined(assembly, typeof(SingleAttribute<int>))); + Assert(((ICustomAttributeProvider)assembly).IsDefined(typeof(SingleAttribute<int>), true)); + Assert(CustomAttributeExtensions.IsDefined(assembly, typeof(SingleAttribute<bool>))); + Assert(((ICustomAttributeProvider)assembly).IsDefined(typeof(SingleAttribute<bool>), true)); + + TypeInfo programTypeInfo = typeof(Class).GetTypeInfo(); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<int>>(programTypeInfo) != null); + Assert(((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute<int>), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<bool>>(programTypeInfo) != null); + Assert(((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute<bool>), true) != null); + Assert(CustomAttributeExtensions.IsDefined(programTypeInfo, typeof(SingleAttribute<int>))); + Assert(((ICustomAttributeProvider)programTypeInfo).IsDefined(typeof(SingleAttribute<int>), true)); + Assert(CustomAttributeExtensions.IsDefined(programTypeInfo, typeof(SingleAttribute<bool>))); + Assert(((ICustomAttributeProvider)programTypeInfo).IsDefined(typeof(SingleAttribute<bool>), true)); + + var propertyPropertyInfo = typeof(Class).GetTypeInfo().GetProperty(nameof(Class.Property)); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<int>>(propertyPropertyInfo) != null); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).GetCustomAttributes(typeof(SingleAttribute<int>), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<bool>>(propertyPropertyInfo) != null); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).GetCustomAttributes(typeof(SingleAttribute<bool>), true) != null); + Assert(CustomAttributeExtensions.IsDefined(propertyPropertyInfo, typeof(SingleAttribute<int>))); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).IsDefined(typeof(SingleAttribute<int>), true)); + Assert(CustomAttributeExtensions.IsDefined(propertyPropertyInfo, typeof(SingleAttribute<bool>))); + Assert(((ICustomAttributeProvider)propertyPropertyInfo).IsDefined(typeof(SingleAttribute<bool>), true)); + + var deriveTypeInfo = typeof(Class.Derive).GetTypeInfo(); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<int>>(deriveTypeInfo, false) == null); + Assert(((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(typeof(SingleAttribute<int>), true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<bool>>(deriveTypeInfo, false) == null); + Assert(((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(typeof(SingleAttribute<bool>), true) != null); + Assert(!CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute<int>), false)); + Assert(!CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute<bool>), false)); + + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<int>>(deriveTypeInfo, true) != null); + Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<bool>>(deriveTypeInfo, true) != null); + Assert(CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute<int>), true)); + Assert(((ICustomAttributeProvider)deriveTypeInfo).IsDefined(typeof(SingleAttribute<int>), true)); + Assert(CustomAttributeExtensions.IsDefined(deriveTypeInfo, typeof(SingleAttribute<bool>), true)); + Assert(((ICustomAttributeProvider)deriveTypeInfo).IsDefined(typeof(SingleAttribute<bool>), true)); + + var a1 = CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, true); + AssertAny(a1, a => a is SingleAttribute<int>); + AssertAny(a1, a => a is SingleAttribute<bool>); + AssertAny(a1, a => (a as MultiAttribute<int>)?.Value == 0); + AssertAny(a1, a => (a as MultiAttribute<int>)?.Value == 1); + AssertAny(a1, a => (a as MultiAttribute<int>)?.Value == 2); + AssertAny(a1, a => (a as MultiAttribute<bool>)?.Value == false); + AssertAny(a1, a => (a as MultiAttribute<bool>)?.Value == true, 2); + AssertAny(a1, a => (a as MultiAttribute<bool?>)?.Value == null); + + var b1 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(true); + AssertAny(b1, a => a is SingleAttribute<int>); + AssertAny(b1, a => a is SingleAttribute<bool>); + AssertAny(b1, a => (a as MultiAttribute<int>)?.Value == 0); + AssertAny(b1, a => (a as MultiAttribute<int>)?.Value == 1); + AssertAny(b1, a => (a as MultiAttribute<int>)?.Value == 2); + AssertAny(b1, a => (a as MultiAttribute<bool>)?.Value == false); + AssertAny(b1, a => (a as MultiAttribute<bool>)?.Value == true, 2); + AssertAny(b1, a => (a as MultiAttribute<bool?>)?.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<int>); + AssertAny(a3, a => a is SingleAttribute<bool>); + AssertAny(a3, a => (a as MultiAttribute<int>)?.Value == 0); + AssertAny(a3, a => (a as MultiAttribute<int>)?.Value == 1); + AssertAny(a3, a => (a as MultiAttribute<int>)?.Value == 2); + AssertAny(a3, a => (a as MultiAttribute<bool>)?.Value == false); + AssertAny(a3, a => (a as MultiAttribute<bool>)?.Value == true); + + var b3 = ((ICustomAttributeProvider)deriveTypeInfo).GetCustomAttributes(true); + AssertAny(b3, a => a is SingleAttribute<int>); + AssertAny(b3, a => a is SingleAttribute<bool>); + AssertAny(b3, a => (a as MultiAttribute<int>)?.Value == 0); + AssertAny(b3, a => (a as MultiAttribute<int>)?.Value == 1); + AssertAny(b3, a => (a as MultiAttribute<int>)?.Value == 2); + AssertAny(b3, a => (a as MultiAttribute<bool>)?.Value == false); + AssertAny(b3, a => (a as MultiAttribute<bool>)?.Value == true); + + var a4 = CustomAttributeExtensions.GetCustomAttributes<SingleAttribute<int>>(programTypeInfo, true); + AssertAny(a4, a => a is SingleAttribute<int>); + + var b4 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute<int>), true); + AssertAny(b4, a => a is SingleAttribute<int>); + + var a5 = CustomAttributeExtensions.GetCustomAttributes<SingleAttribute<bool>>(programTypeInfo); + AssertAny(a5, a => a is SingleAttribute<bool>); + + var b5 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute<bool>), true); + AssertAny(b5, a => a is SingleAttribute<bool>); + + var a6 = CustomAttributeExtensions.GetCustomAttributes<MultiAttribute<int>>(programTypeInfo, true); + AssertAny(a6, a => (a as MultiAttribute<int>)?.Value == 0); + AssertAny(a6, a => (a as MultiAttribute<int>)?.Value == 1); + AssertAny(a6, a => (a as MultiAttribute<int>)?.Value == 2); + + var b6 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute<int>), true); + AssertAny(b6, a => (a as MultiAttribute<int>)?.Value == 0); + AssertAny(b6, a => (a as MultiAttribute<int>)?.Value == 1); + AssertAny(b6, a => (a as MultiAttribute<int>)?.Value == 2); + + var a7 = CustomAttributeExtensions.GetCustomAttributes<MultiAttribute<bool>>(programTypeInfo, true); + AssertAny(a7, a => (a as MultiAttribute<bool>)?.Value == false); + AssertAny(a7, a => (a as MultiAttribute<bool>)?.Value == true); + + var b7 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute<bool>), true); + AssertAny(b7, a => (a as MultiAttribute<bool>)?.Value == false); + AssertAny(b7, a => (a as MultiAttribute<bool>)?.Value == true); + + var a8 = CustomAttributeExtensions.GetCustomAttributes<MultiAttribute<bool?>>(programTypeInfo, true); + AssertAny(a8, a => (a as MultiAttribute<bool?>)?.Value == null); + + var b8 = ((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute<bool?>), true); + AssertAny(b8, a => (a as MultiAttribute<bool?>)?.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<object> source, Func<Attribute, bool> 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 0000000000..3737ee9f4f --- /dev/null +++ b/tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>GenericAttributeTests</AssemblyName> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <OutputType>Exe</OutputType> + <CLRTestKind>BuildAndRun</CLRTestKind> + <CLRTestPriority>1</CLRTestPriority> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="GenericAttributeTests.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="GenericAttributeMetadata.ilproj" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file |