diff options
author | Marek Safar <marek.safar@gmail.com> | 2022-02-22 15:47:18 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2022-02-22 15:47:18 +0300 |
commit | fcbb234133cf1ffba99373b46b5f21edb3bc3787 (patch) | |
tree | 84bf6642559bbe1564ab01d02bfa9300aa5bc2bd | |
parent | 0780d4e15ef42b56a4e40dafac0d5486f09ce005 (diff) | |
parent | f7b64f756021c546d303e55413f10967728ad8ba (diff) |
Merge remote-tracking branch 'upstream/master'
-rw-r--r-- | Mono.Cecil/AssemblyReader.cs | 6 | ||||
-rw-r--r-- | Mono.Cecil/AssemblyWriter.cs | 12 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/CompilationService.cs | 2 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/CustomAttributesTests.cs | 101 | ||||
-rw-r--r-- | Test/Resources/cs/CustomAttributes.cs | 37 |
5 files changed, 156 insertions, 2 deletions
diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs index b66c162..ee2c229 100644 --- a/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/AssemblyReader.cs @@ -3598,6 +3598,12 @@ namespace Mono.Cecil { object ReadCustomAttributeElementValue (TypeReference type) { var etype = type.etype; + if (etype == ElementType.GenericInst) { + // The only way to get a generic here is that it's an enum on a generic type + // so for enum we don't need to know the generic arguments (they have no effect) + type = type.GetElementType (); + etype = type.etype; + } switch (etype) { case ElementType.String: diff --git a/Mono.Cecil/AssemblyWriter.cs b/Mono.Cecil/AssemblyWriter.cs index 5799f07..3843e85 100644 --- a/Mono.Cecil/AssemblyWriter.cs +++ b/Mono.Cecil/AssemblyWriter.cs @@ -2999,6 +2999,10 @@ namespace Mono.Cecil { else WriteCustomAttributeEnumValue (type, value); break; + case ElementType.GenericInst: + // Generic instantiation can only happen for an enum (no other generic like types can appear in attribute value) + WriteCustomAttributeEnumValue (type, value); + break; default: WritePrimitiveValue (value); break; @@ -3105,6 +3109,14 @@ namespace Mono.Cecil { WriteTypeReference (type); } return; + case ElementType.GenericInst: + // Generic instantiation can really only happen if it's an enum type since no other + // types are allowed in the attribute value. + // Enums are special in attribute data, they're encoded as ElementType.Enum followed by a typeref + // followed by the value. + WriteElementType (ElementType.Enum); + WriteTypeReference (type); + return; default: WriteElementType (etype); return; diff --git a/Test/Mono.Cecil.Tests/CompilationService.cs b/Test/Mono.Cecil.Tests/CompilationService.cs index 0c9d35c..f7ecc4c 100644 --- a/Test/Mono.Cecil.Tests/CompilationService.cs +++ b/Test/Mono.Cecil.Tests/CompilationService.cs @@ -186,7 +186,7 @@ namespace Mono.Cecil.Tests { case ".cs": return CS.CSharpCompilation.Create ( assemblyName, - new [] { CS.SyntaxFactory.ParseSyntaxTree (source) }, + new [] { CS.SyntaxFactory.ParseSyntaxTree (source, new CS.CSharpParseOptions (preprocessorSymbols: new string [] { "NET_CORE" })) }, references, new CS.CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release)); default: diff --git a/Test/Mono.Cecil.Tests/CustomAttributesTests.cs b/Test/Mono.Cecil.Tests/CustomAttributesTests.cs index 0c8524a..a406c41 100644 --- a/Test/Mono.Cecil.Tests/CustomAttributesTests.cs +++ b/Test/Mono.Cecil.Tests/CustomAttributesTests.cs @@ -546,6 +546,105 @@ namespace Mono.Cecil.Tests { module.Dispose (); } +#if NET_CORE + [Test] + public void BoxedEnumOnGenericArgumentOnType () + { + TestCSharp ("CustomAttributes.cs", module => { + var valueEnumGenericType = module.GetType ("BoxedValueEnumOnGenericType"); + + Assert.IsTrue (valueEnumGenericType.HasCustomAttributes); + Assert.AreEqual (1, valueEnumGenericType.CustomAttributes.Count); + + var attribute = valueEnumGenericType.CustomAttributes [0]; + Assert.AreEqual ("System.Void FooAttribute::.ctor(System.Object,System.Object)", + attribute.Constructor.FullName); + + Assert.IsTrue (attribute.HasConstructorArguments); + Assert.AreEqual (2, attribute.ConstructorArguments.Count); + + AssertCustomAttributeArgument ("(Object:(GenericWithEnum`1/OnGenericNumber<System.Int32>:0))", attribute.ConstructorArguments [0]); + AssertCustomAttributeArgument ("(Object:(GenericWithEnum`1/OnGenericNumber<System.String>:1))", attribute.ConstructorArguments [1]); + }); + } + + [Test] + public void EnumOnGenericArgumentOnType () + { + TestCSharp ("CustomAttributes.cs", module => { + var valueEnumGenericType = module.GetType ("ValueEnumOnGenericType"); + + Assert.IsTrue (valueEnumGenericType.HasCustomAttributes); + Assert.AreEqual (1, valueEnumGenericType.CustomAttributes.Count); + + var attribute = valueEnumGenericType.CustomAttributes [0]; + Assert.AreEqual ("System.Void FooAttribute::.ctor(GenericWithEnum`1/OnGenericNumber<Bingo>)", + attribute.Constructor.FullName); + + Assert.IsTrue (attribute.HasConstructorArguments); + Assert.AreEqual (1, attribute.ConstructorArguments.Count); + + AssertCustomAttributeArgument ("(GenericWithEnum`1/OnGenericNumber<Bingo>:1)", attribute.ConstructorArguments [0]); + }); + } + + [Test] + public void EnumOnGenericFieldOnType () + { + TestCSharp ("CustomAttributes.cs", module => { + var valueEnumGenericType = module.GetType ("FieldEnumOnGenericType"); + + Assert.IsTrue (valueEnumGenericType.HasCustomAttributes); + Assert.AreEqual (1, valueEnumGenericType.CustomAttributes.Count); + + var attribute = valueEnumGenericType.CustomAttributes [0]; + var argument = attribute.Fields.Where (a => a.Name == "NumberEnumField").First ().Argument; + + AssertCustomAttributeArgument ("(GenericWithEnum`1/OnGenericNumber<System.Byte>:0)", argument); + }); + } + + [Test] + public void EnumOnGenericPropertyOnType () + { + TestCSharp ("CustomAttributes.cs", module => { + var valueEnumGenericType = module.GetType ("PropertyEnumOnGenericType"); + + Assert.IsTrue (valueEnumGenericType.HasCustomAttributes); + Assert.AreEqual (1, valueEnumGenericType.CustomAttributes.Count); + + var attribute = valueEnumGenericType.CustomAttributes [0]; + var argument = attribute.Properties.Where (a => a.Name == "NumberEnumProperty").First ().Argument; + + AssertCustomAttributeArgument ("(GenericWithEnum`1/OnGenericNumber<System.Byte>:1)", argument); + }); + } + + [Test] + public void EnumDeclaredInGenericTypeArray () + { + TestCSharp ("CustomAttributes.cs", module => { + var type = module.GetType ("WithAttributeUsingNestedEnumArray"); + var attributes = type.CustomAttributes; + Assert.AreEqual (1, attributes.Count); + var attribute = attributes [0]; + Assert.AreEqual (1, attribute.Fields.Count); + var arg = attribute.Fields [0].Argument; + Assert.AreEqual ("System.Object", arg.Type.FullName); + + var argumentValue = (CustomAttributeArgument)arg.Value; + Assert.AreEqual ("GenericWithEnum`1/OnGenericNumber<System.String>[]", argumentValue.Type.FullName); + var argumentValues = (CustomAttributeArgument [])argumentValue.Value; + + Assert.AreEqual ("GenericWithEnum`1/OnGenericNumber<System.String>", argumentValues [0].Type.FullName); + Assert.AreEqual (0, (int)argumentValues [0].Value); + + Assert.AreEqual ("GenericWithEnum`1/OnGenericNumber<System.String>", argumentValues [1].Type.FullName); + Assert.AreEqual (1, (int)argumentValues [1].Value); + }); + } +#endif + static void AssertCustomAttribute (string expected, CustomAttribute attribute) { Assert.AreEqual (expected, PrettyPrint (attribute)); @@ -643,7 +742,7 @@ namespace Mono.Cecil.Tests { if (type.IsArray) { ArrayType array = (ArrayType) type; signature.AppendFormat ("{0}[]", array.ElementType.etype.ToString ()); - } else if (type.etype == ElementType.None) { + } else if (type.etype == ElementType.None || type.etype == ElementType.GenericInst) { signature.Append (type.FullName); } else signature.Append (type.etype.ToString ()); diff --git a/Test/Resources/cs/CustomAttributes.cs b/Test/Resources/cs/CustomAttributes.cs index 11939ed..530d654 100644 --- a/Test/Resources/cs/CustomAttributes.cs +++ b/Test/Resources/cs/CustomAttributes.cs @@ -11,6 +11,14 @@ enum Bingo : short { Binga = 4, } +class GenericWithEnum<T> { + public enum OnGenericNumber + { + One, + Two + } +} + /* in System.Security.AccessControl @@ -70,6 +78,10 @@ class FooAttribute : Attribute { { } + public FooAttribute (GenericWithEnum<Bingo>.OnGenericNumber number) + { + } + public int Bang { get { return 0; } set {} } public string Fiou { get { return "fiou"; } set {} } @@ -77,6 +89,9 @@ class FooAttribute : Attribute { public string [] PanPan; public Type Chose; + + public GenericWithEnum<byte>.OnGenericNumber NumberEnumField; + public GenericWithEnum<byte>.OnGenericNumber NumberEnumProperty { get; set; } } [Foo ("bar")] @@ -160,3 +175,25 @@ class Parent { [Foo ("Foo\0Bar\0")] class NullCharInString { } + +#if NET_CORE +[Foo (GenericWithEnum<int>.OnGenericNumber.One, GenericWithEnum<string>.OnGenericNumber.Two)] +class BoxedValueEnumOnGenericType { +} + +[Foo (GenericWithEnum<Bingo>.OnGenericNumber.Two)] +class ValueEnumOnGenericType { +} + +[Foo (NumberEnumField = GenericWithEnum<byte>.OnGenericNumber.One)] +class FieldEnumOnGenericType { +} + +[Foo(NumberEnumProperty = GenericWithEnum<byte>.OnGenericNumber.Two)] +class PropertyEnumOnGenericType { +} + +[Foo(Pan = new[] { GenericWithEnum<string>.OnGenericNumber.One, GenericWithEnum<string>.OnGenericNumber.Two })] +class WithAttributeUsingNestedEnumArray { +} +#endif
\ No newline at end of file |