From 05ac115223c84684075bcfa7aefbfa7e503e18b5 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 2 Aug 2024 16:13:52 -0700 Subject: [PATCH 1/3] Fix some core type references --- .../src/System/Reflection/Emit/ArrayMethod.cs | 4 +- .../System/Reflection/Emit/TypeBuilderImpl.cs | 3 +- .../AssemblySaveEnumBuilderTests.cs | 35 ++++++++++++++ .../AssemblySaveModuleBuilderTests.cs | 48 +++++++++++++++++++ 4 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs index e619c24ca112d0..3114e42d55ec62 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ArrayMethod.cs @@ -18,10 +18,10 @@ internal sealed class ArrayMethod : MethodInfo #region Constructor // This is a kind of MethodInfo to represent methods for array type of unbaked type - internal ArrayMethod(ModuleBuilder module, Type arrayClass, string methodName, + internal ArrayMethod(ModuleBuilderImpl module, Type arrayClass, string methodName, CallingConventions callingConvention, Type? returnType, Type[]? parameterTypes) { - _returnType = returnType ?? typeof(void); + _returnType = returnType ?? module.GetTypeFromCoreAssembly(CoreTypeId.Void); if (parameterTypes != null) { _parameterTypes = new Type[parameterTypes.Length]; diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs index 887ee1afb891f5..2c1cdcae7c8a4f 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs @@ -439,6 +439,7 @@ protected override FieldBuilder DefineUninitializedDataCore(string name, int siz return DefineDataHelper(name, new byte[size], size, attributes); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:DynamicallyAccessedMembers", Justification = "Types are preserved via ModuleBuilderImpl.s_coreTypes")] private FieldBuilder DefineDataHelper(string name, byte[] data, int size, FieldAttributes attributes) { ArgumentException.ThrowIfNullOrEmpty(name); @@ -456,7 +457,7 @@ private FieldBuilder DefineDataHelper(string name, byte[] data, int size, FieldA TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.ExplicitLayout | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass; // Define the backing value class - valueClassType = (TypeBuilderImpl)_module.DefineType(strValueClassName, typeAttributes, typeof(ValueType), PackingSize.Size1, size); + valueClassType = (TypeBuilderImpl)_module.DefineType(strValueClassName, typeAttributes, _module.GetTypeFromCoreAssembly(CoreTypeId.ValueType), PackingSize.Size1, size); valueClassType.CreateType(); } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs index 29a94bacd15d84..3c569b815da639 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs @@ -67,6 +67,7 @@ public void DefineLiteral(Type underlyingType, object literalValue) EnumBuilder enumBuilder = CreateAssemblyAndDefineEnum(out PersistedAssemblyBuilder assemblyBuilder, out TypeBuilder type, underlyingType); FieldBuilder literal = enumBuilder.DefineLiteral("FieldOne", literalValue); enumBuilder.CreateTypeInfo(); + Assert.True(enumBuilder.IsEnum); type.CreateTypeInfo(); assemblyBuilder.Save(file.Path); @@ -79,15 +80,49 @@ public void DefineLiteral(Type underlyingType, object literalValue) Assert.True(testEnum.IsEnum); AssemblySaveTools.AssertTypeProperties(enumBuilder, testEnum); Assert.Equal(underlyingType.FullName, testEnum.GetEnumUnderlyingType().FullName); + Assert.Equal(mlc.CoreAssembly.GetType("System.Enum"), testEnum.BaseType); FieldInfo testField = testEnum.GetField("FieldOne"); Assert.Equal(enumBuilder.Name, testField.DeclaringType.Name); Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, literal.Attributes); Assert.Equal(enumBuilder.AsType().FullName, testField.FieldType.FullName); + Assert.Equal(testEnum, testField.FieldType); } } } + [Fact] + public void CreateEnumWithMlc() + { + using (var stream = new MemoryStream()) + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(PopulateAssemblyName(), mlc.CoreAssembly); + ModuleBuilder mb = ab.DefineDynamicModule("My Module"); + Type intType = mlc.CoreAssembly.GetType("System.Int32"); + EnumBuilder enumBuilder = mb.DefineEnum("TestEnum", TypeAttributes.Public, typeof(int)); + FieldBuilder field = enumBuilder.DefineLiteral("Default", 0); + + enumBuilder.CreateTypeInfo(); + Assert.True(enumBuilder.IsEnum); + Assert.Equal(enumBuilder, field.FieldType); + + ab.Save(stream); + Assembly assemblyFromStream = mlc.LoadFromStream(stream); + Type createdEnum = assemblyFromStream.GetType("TestEnum"); + + Assert.True(createdEnum.IsEnum); + AssemblySaveTools.AssertTypeProperties(enumBuilder, createdEnum); + Assert.Equal(mlc.CoreAssembly.GetType("System.Enum"), createdEnum.BaseType); + Assert.Equal(intType, createdEnum.GetEnumUnderlyingType()); + + FieldInfo testField = createdEnum.GetField("Default"); + Assert.Equal(createdEnum, testField.FieldType); + Assert.Equal(typeof(int), enumBuilder.GetEnumUnderlyingType()); + Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, testField.Attributes); + } + } + [Theory] [InlineData(0, "TestEnum[]")] [InlineData(1, "TestEnum[]")] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs index 959ea0022d5ce3..0c8a7a2aae81cf 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs @@ -127,6 +127,25 @@ public void DefineUninitializedDataTest(FieldAttributes attributes) Assert.True(field.IsStatic); Assert.True((field.Attributes & FieldAttributes.HasFieldRVA) != 0); Assert.Equal(attributes | FieldAttributes.Static | FieldAttributes.HasFieldRVA, field.Attributes); + Assert.Equal(typeof(ValueType), field.FieldType.BaseType); + } + } + + [Fact] + public void DefineUninitializedDataFromMLC() + { + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), mlc.CoreAssembly); + ModuleBuilder module = ab.DefineDynamicModule("MyModule"); + FieldBuilder field = module.DefineUninitializedData("UninitializedDataField", 100, FieldAttributes.Public); + + Assert.Equal("UninitializedDataField", field.Name); + Assert.True(field.IsStatic); + Assert.True((field.Attributes & FieldAttributes.HasFieldRVA) != 0); + Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasFieldRVA, field.Attributes); + Assert.NotEqual(typeof(ValueType), field.FieldType.BaseType); + Assert.Equal(mlc.CoreAssembly.GetType("System.ValueType"), field.FieldType.BaseType); } } @@ -354,5 +373,34 @@ public void GetArrayMethod_InvalidArgument_ThrowsArgumentException() AssertExtensions.Throws("parameterTypes", () => module.GetArrayMethod(typeof(string[]), "TestMethod", CallingConventions.Standard, null, [null])); AssertExtensions.Throws(null, () => module.GetArrayMethod(typeof(Array), "TestMethod", CallingConventions.Standard, null, null)); } + + [Fact] + public void GetArrayMethodNullReturnType() + { + ModuleBuilder module = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")).DefineDynamicModule("MyModule"); + MethodInfo method = module.GetArrayMethod(typeof(int[]), "MethodName", CallingConventions.Standard, null, null); + + Assert.Equal(typeof(int[]), method.DeclaringType); + Assert.Equal("MethodName", method.Name); + Assert.Equal(CallingConventions.Standard, method.CallingConvention); + Assert.Equal(typeof(void), method.ReturnType); + } + + [Fact] + public void GetArrayMethodNullReturnTypeFromMLC() + { + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + ModuleBuilder module = new PersistedAssemblyBuilder(new AssemblyName("MyAssembly"), mlc.CoreAssembly).DefineDynamicModule("MyModule"); + Type arrayType = mlc.CoreAssembly.GetType("System.Int32").MakeArrayType(); + MethodInfo method = module.GetArrayMethod(arrayType, "MethodName", CallingConventions.Standard, null, null); + + Assert.Equal(arrayType, method.DeclaringType); + Assert.Equal("MethodName", method.Name); + Assert.Equal(CallingConventions.Standard, method.CallingConvention); + Assert.NotEqual(typeof(void), method.ReturnType); + Assert.Equal(mlc.CoreAssembly.GetType("System.Void"), method.ReturnType); + } + } } } From 9f12b1adc9578d1b653b0dda95bbec8357c8f441 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Sat, 3 Aug 2024 18:25:47 -0700 Subject: [PATCH 2/3] Update src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs --- .../src/System/Reflection/Emit/TypeBuilderImpl.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs index 2c1cdcae7c8a4f..950a7aee432016 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs @@ -439,7 +439,8 @@ protected override FieldBuilder DefineUninitializedDataCore(string name, int siz return DefineDataHelper(name, new byte[size], size, attributes); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:DynamicallyAccessedMembers", Justification = "Types are preserved via ModuleBuilderImpl.s_coreTypes")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:DynamicallyAccessedMembers", Justification = "The members of 'ValueType' are not referenced in this context")] +```suggestion private FieldBuilder DefineDataHelper(string name, byte[] data, int size, FieldAttributes attributes) { ArgumentException.ThrowIfNullOrEmpty(name); From 7e1f617e3de42f281452b3220473162d6952906d Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Wed, 7 Aug 2024 12:21:34 -0500 Subject: [PATCH 3/3] Remove inadvertent text --- .../src/System/Reflection/Emit/TypeBuilderImpl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs index 950a7aee432016..5f46a70bcc7f60 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs @@ -440,7 +440,6 @@ protected override FieldBuilder DefineUninitializedDataCore(string name, int siz } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:DynamicallyAccessedMembers", Justification = "The members of 'ValueType' are not referenced in this context")] -```suggestion private FieldBuilder DefineDataHelper(string name, byte[] data, int size, FieldAttributes attributes) { ArgumentException.ThrowIfNullOrEmpty(name);