summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Avni <avi.avni@gmail.com>2018-04-17 17:14:34 +0300
committerJan Kotas <jkotas@microsoft.com>2018-04-17 07:14:34 -0700
commit1d406b1a0ad54348dbdda4c9117897921d95f950 (patch)
treec76cd400804ccee62a5565626b27427fd3609be8
parentbcfb0c959bbac65110c22b695e73249b8dddbd18 (diff)
downloadcoreclr-1d406b1a0ad54348dbdda4c9117897921d95f950.tar.gz
coreclr-1d406b1a0ad54348dbdda4c9117897921d95f950.tar.bz2
coreclr-1d406b1a0ad54348dbdda4c9117897921d95f950.zip
Enable generic attributes (#9189)
-rw-r--r--src/mscorlib/src/System/Reflection/CustomAttribute.cs10
-rw-r--r--src/vm/callhelpers.h34
-rw-r--r--src/vm/customattribute.cpp20
-rw-r--r--src/vm/customattribute.h2
-rw-r--r--tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs78
-rw-r--r--tests/src/reflection/GenericAttribute/GenericAttributeMetadata.il223
-rw-r--r--tests/src/reflection/GenericAttribute/GenericAttributeMetadata.ilproj35
-rw-r--r--tests/src/reflection/GenericAttribute/GenericAttributeTests.cs163
-rw-r--r--tests/src/reflection/GenericAttribute/GenericAttributeTests.csproj31
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