From 603581d525a7d19c5c11330217ad7bab104fb638 Mon Sep 17 00:00:00 2001 From: snakex64 Date: Mon, 28 Oct 2024 18:55:18 -0400 Subject: [PATCH 1/6] Added GetProperties, GetProperty, GetInterface --- .../ref/System.Reflection.Emit.cs | 2 +- .../System/Reflection/Emit/TypeBuilderImpl.cs | 120 +++++++++++++++++- .../AssemblySavePropertyBuilderTests.cs | 88 +++++++++++++ .../AssemblySaveTypeBuilderAPIsTests.cs | 35 +++++ 4 files changed, 240 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs index 2847b868711dec..c1bc5ed7298967 100644 --- a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs +++ b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs @@ -660,7 +660,7 @@ public void DefineMethodOverride(System.Reflection.MethodInfo methodInfoBody, Sy [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] public override System.Reflection.PropertyInfo[] GetProperties(System.Reflection.BindingFlags bindingAttr) { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] - protected override System.Reflection.PropertyInfo GetPropertyImpl(string name, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, System.Type? returnType, System.Type[]? types, System.Reflection.ParameterModifier[]? modifiers) { throw null; } + protected override System.Reflection.PropertyInfo? GetPropertyImpl(string name, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, System.Type? returnType, System.Type[]? types, System.Reflection.ParameterModifier[]? modifiers) { throw null; } protected override bool HasElementTypeImpl() { throw null; } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] public override object? InvokeMember(string name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder? binder, object? target, object?[]? args, System.Reflection.ParameterModifier[]? modifiers, System.Globalization.CultureInfo? culture, string[]? namedParameters) { throw null; } 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 a5c00306657d45..bdf84a57bdea88 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 @@ -891,18 +891,130 @@ public override FieldInfo[] GetFields(BindingFlags bindingAttr) return candidates.ToArray(); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063:UnrecognizedReflectionPattern")] [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] - public override Type? GetInterface(string name, bool ignoreCase) => throw new NotSupportedException(); + public override Type? GetInterface(string name, bool ignoreCase) + { + ArgumentNullException.ThrowIfNull(name); + ThrowIfNotCreated(); + + Type[] interfaces = GetInterfaces(); + + Type? match = null; + StringComparison compare = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + for (int i = 0; i < interfaces.Length; ++i) + { + Type interfaceType = interfaces[i]; + + if (name.Equals(interfaceType.Name, compare)) + { + if (match != null) + { + // TypeBuilder doesn't validate for duplicates when fields are defined, throw if duplicates found. + throw new AmbiguousMatchException(SR.Format(SR.AmbiguousMatch_MemberInfo, interfaceType.DeclaringType, interfaceType.Name)); + } + + match = interfaceType; + } + } + + return match; + } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] public override Type[] GetInterfaces() => _interfaces == null ? EmptyTypes : _interfaces.ToArray(); + internal static BindingFlags GetBindingFlags(PropertyBuilderImpl property) + { + MethodInfo? getMethod = property.GetMethod; + MethodInfo? setMethod = property.SetMethod; + + BindingFlags bindingFlags = BindingFlags.Default; + + if (getMethod != null) + { + bindingFlags = GetBindingFlags(getMethod); + } + else if (setMethod != null) + { + bindingFlags = GetBindingFlags(setMethod); + } + + return bindingFlags; + } + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) + { + ThrowIfNotCreated(); + + List candidates = new List(_propertyDefinitions.Count); + foreach (PropertyBuilderImpl property in _propertyDefinitions) + { + BindingFlags fieldFlags = GetBindingFlags(property); + if ((bindingAttr & fieldFlags) == fieldFlags) + { + candidates.Add(property); + } + } + + return candidates.ToArray(); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] - public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => throw new NotSupportedException(); + protected override PropertyInfo? GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder, + Type? returnType, Type[]? types, ParameterModifier[]? modifiers) + { + ArgumentNullException.ThrowIfNull(name); + + List candidates = GetPropertyCandidates(name, bindingAttr, types); + + if (candidates.Count == 0) + return null; + + if (types == null || types.Length == 0) + { + // no arguments + PropertyInfo firstCandidate = candidates[0]; + + if (candidates.Count == 1) + { + if (returnType is not null && !returnType.IsEquivalentTo(firstCandidate.PropertyType)) + return null; + + return firstCandidate; + } + else + { + if (returnType is null) + // if we are here we have no args or property type to select over and we have more than one property with that name + throw new AmbiguousMatchException(SR.Format(SR.AmbiguousMatch_MemberInfo, firstCandidate.DeclaringType, firstCandidate.Name)); + } + } + + binder ??= DefaultBinder; + return binder.SelectProperty(bindingAttr, candidates.ToArray(), returnType, types, modifiers); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] - protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder, - Type? returnType, Type[]? types, ParameterModifier[]? modifiers) => throw new NotSupportedException(); + private List GetPropertyCandidates(string name, BindingFlags bindingAttr, Type[]? types) + { + PropertyInfo[] properties = GetProperties(bindingAttr); + + List candidates = new List(properties.Length); + for (int i = 0; i < properties.Length; i++) + { + PropertyInfo propertyInfo = properties[i]; + if (propertyInfo.Name == name && + (types == null || (propertyInfo.GetIndexParameters().Length == types.Length))) + { + candidates.Add(propertyInfo); + } + } + + return candidates; + } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotSupportedException(); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs index a8cd0754c853fb..6bff85e29e928e 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs @@ -13,6 +13,94 @@ namespace System.Reflection.Emit.Tests [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] public class AssemblySavePropertyBuilderTests { + [Fact] + public void GetPropertiesAndGetProperty() + { + PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + FieldBuilder field = type.DefineField("TestField", typeof(int), FieldAttributes.Private | FieldAttributes.Static); + CreateProperty("PublicGetSet", isPublic: true, isStatic: false, hasSet: true); + CreateProperty("PublicGet", isPublic: true, isStatic: false, hasSet: false); + + CreateProperty("PrivateGetSet", isPublic: false, isStatic: false, hasSet: false); + CreateProperty("PrivateGet", isPublic: false, isStatic: false, hasSet: false); + + CreateProperty("StaticPublicGetSet", isPublic: true, isStatic: true, hasSet: true); + CreateProperty("StaticPublicGet", isPublic: true, isStatic: true, hasSet: true); + + CreateProperty("StaticPrivateGetSet", isPublic: false, isStatic: true, hasSet: true); + CreateProperty("StaticPrivateGet", isPublic: false, isStatic: true, hasSet: true); + + // Try get before creation + Assert.Throws(() => type.GetProperties()); + Assert.Throws(() => type.GetProperty("PublicGetSet")); + + // Create the type + type.CreateType(); + + // By default GetProperties doesn't return private properties + Assert.Equal(4, type.GetProperties().Length); + Assert.True(type.GetProperties().All(x => x.Name.Contains("Public"))); + + // get all properties + PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + Assert.Equal(8, properties.Length); + + // get only private properties + properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + Assert.Equal(4, properties.Length); + Assert.True(properties.All(x => x.Name.Contains("Private"))); + + // get only static properties + properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + Assert.Equal(4, properties.Length); + Assert.True(properties.All(x => x.Name.Contains("Static"))); + + // get public property by name only + PropertyInfo? property = type.GetProperty("PublicGetSet"); + Assert.NotNull(property); + Assert.Equal("PublicGetSet", property.Name); + + // get public property by name and binding flags + property = type.GetProperty("PublicGetSet", BindingFlags.Public | BindingFlags.Instance); + Assert.NotNull(property); + Assert.Equal("PublicGetSet", property.Name); + + // get public property by name and binding flags when there is not "set" method + property = type.GetProperty("StaticPublicGet", BindingFlags.Public | BindingFlags.Static); + Assert.NotNull(property); + Assert.Equal("StaticPublicGet", property.Name); + + // Returns null when not found + Assert.Null(type.GetProperty("NotFound")); + Assert.Null(type.GetProperty("PublicGetSet", BindingFlags.NonPublic | BindingFlags.Instance)); + Assert.Null(type.GetProperty("PublicGetSet", BindingFlags.Public | BindingFlags.Static)); + + + void CreateProperty(string name, bool isPublic, bool isStatic, bool hasSet) + { + MethodAttributes methodAttributes = (isPublic ? MethodAttributes.Public : MethodAttributes.Private) | (isStatic ? MethodAttributes.Static : default) | MethodAttributes.SpecialName | MethodAttributes.HideBySig; + PropertyBuilder property = type.DefineProperty(name, PropertyAttributes.SpecialName | PropertyAttributes.HasDefault, typeof(int), null); + + MethodBuilder getMethod = type.DefineMethod($"{name}_GetMethod", methodAttributes, typeof(int), null); + ILGenerator getterLGenerator = getMethod.GetILGenerator(); + getterLGenerator.Emit(OpCodes.Ldarg_0); + getterLGenerator.Emit(OpCodes.Ldfld, field); + getterLGenerator.Emit(OpCodes.Ret); + property.SetGetMethod(getMethod); + + if (hasSet) + { + MethodBuilder setMethod = type.DefineMethod($"{name}_SetMethod", methodAttributes, typeof(void), [typeof(int)]); + ILGenerator setterILGenerator = setMethod.GetILGenerator(); + setterILGenerator.Emit(OpCodes.Ldarg_0); + setterILGenerator.Emit(OpCodes.Ldarg_1); + setterILGenerator.Emit(OpCodes.Stfld, field); + setterILGenerator.Emit(OpCodes.Ret); + property.SetSetMethod(setMethod); + } + } + } + [Fact] public void SetPropertyAccessorsAndOtherValues() { diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs index 54199f67e1f989..985633d7f1a8ec 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs @@ -374,6 +374,41 @@ public void GetInterfaceMap_Validations() Assert.Throws(() => type.GetInterfaceMap(typeof(InterfaceWithMethod))); // not implemented } + [Fact] + public void GetInterface_Validations() + { + PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + ModuleBuilder module = ab.GetDynamicModule("MyModule"); + + TypeBuilder interfaceType = module.DefineType("InterfaceType", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract, parent: null); + MethodBuilder svmInterface = interfaceType.DefineMethod("InterfaceMethod1", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, CallingConventions.Standard, typeof(int), Type.EmptyTypes); + MethodBuilder mInterface = interfaceType.DefineMethod("InterfaceMethod2", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, typeof(string), Array.Empty()); + MethodBuilder vmInterface = interfaceType.DefineMethod("InterfaceMethod3", MethodAttributes.Assembly | MethodAttributes.Virtual | MethodAttributes.Abstract, CallingConventions.HasThis, typeof(void), [typeof(bool)]); + Type interfaceTypeActual = interfaceType.CreateType(); + + // Implicit implementations (same name, signatures) + TypeBuilder implType = module.DefineType("ImplType", TypeAttributes.Public, parent: typeof(Impl), new Type[] { interfaceTypeActual }); + MethodBuilder mImpl = implType.DefineMethod("InterfaceMethod2", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), Array.Empty()); + ILGenerator ilGenerator = mImpl.GetILGenerator(); + ilGenerator.Emit(OpCodes.Ldstr, "Hello"); + ilGenerator.Emit(OpCodes.Ret); + MethodBuilder m2Impl = implType.DefineMethod("InterfaceMethod3", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), [typeof(bool)]); + ilGenerator = m2Impl.GetILGenerator(); + ilGenerator.Emit(OpCodes.Ldc_I4_1); + ilGenerator.Emit(OpCodes.Ret); + + Type implTypeActual = implType.CreateType(); + + Type? interfaceReceived = implTypeActual.GetInterface("InterfaceType"); + Assert.Equal(interfaceTypeActual, interfaceReceived); + + interfaceReceived = implTypeActual.GetInterface("interfacetype", false); + Assert.Null(interfaceReceived); + + interfaceReceived = implTypeActual.GetInterface("interfacetype", true); + Assert.NotNull(interfaceReceived); + } + public interface InterfaceDerivedFromOtherInterface : DefineMethodOverrideInterface { public string M2(int a); From b25d8edd09f580860a1f4d8b7d381b4a41147ce4 Mon Sep 17 00:00:00 2001 From: Pascal Arnold Date: Tue, 29 Oct 2024 19:37:36 -0400 Subject: [PATCH 2/6] Added GetNestedType and GetNestedTypes --- .../Reflection/Emit/ModuleBuilderImpl.cs | 14 ++++++ .../System/Reflection/Emit/TypeBuilderImpl.cs | 45 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs index 5d242a710ae2b1..175ddbc9d2b8ab 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs @@ -1381,5 +1381,19 @@ protected override ISymbolDocumentWriter DefineDocumentCore(string url, Guid lan { return new SymbolDocumentWriter(url, language); } + + internal List GetNestedTypeBuilders(TypeBuilderImpl declaringType) + { + List nestedTypes = new List(); + foreach (TypeBuilderImpl typeBuilder in _typeDefinitions) + { + if (typeBuilder.DeclaringType == declaringType) + { + nestedTypes.Add(typeBuilder); + } + } + + return nestedTypes; + } } } 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 bdf84a57bdea88..2f929b2e916d2c 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 @@ -1016,11 +1016,52 @@ private List GetPropertyCandidates(string name, BindingFlags bindi return candidates; } + private static BindingFlags GetBindingFlags(TypeBuilderImpl type) + { + BindingFlags bindingFlags = (type.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public ? + BindingFlags.Public : BindingFlags.NonPublic; + + return bindingFlags; + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] - public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotSupportedException(); + public override Type[] GetNestedTypes(BindingFlags bindingAttr) + { + ThrowIfNotCreated(); + List nestedTypes = new List(); + foreach (TypeBuilderImpl type in _module.GetNestedTypeBuilders(this)) + { + BindingFlags typeFlags = GetBindingFlags(type); + if ((bindingAttr & typeFlags) == typeFlags) + { + nestedTypes.Add(type); + } + } + + return nestedTypes.ToArray(); + } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] - public override Type? GetNestedType(string name, BindingFlags bindingAttr) => throw new NotSupportedException(); + public override Type? GetNestedType(string name, BindingFlags bindingAttr) + { + Type[] types = GetNestedTypes(bindingAttr); + + Type? match = null; + foreach (Type type in types) + { + if (type.Name == name) + { + if (match != null) + { + throw new AmbiguousMatchException(SR.Format(SR.AmbiguousMatch_MemberInfo, type.DeclaringType, type.Name)); + } + + match = type; + } + } + + return match; + } [DynamicallyAccessedMembers(GetAllMembers)] public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) => throw new NotSupportedException(); From 336467a31d699430952bc34e942c9c0f326da43e Mon Sep 17 00:00:00 2001 From: Pascal Arnold Date: Tue, 29 Oct 2024 21:33:31 -0400 Subject: [PATCH 3/6] Added tests --- .../System/Reflection/Emit/TypeBuilderImpl.cs | 3 +- .../AssemblySaveTypeBuilderAPIsTests.cs | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) 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 2f929b2e916d2c..d55c9f53cf758c 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 @@ -1018,8 +1018,7 @@ private List GetPropertyCandidates(string name, BindingFlags bindi private static BindingFlags GetBindingFlags(TypeBuilderImpl type) { - BindingFlags bindingFlags = (type.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public ? - BindingFlags.Public : BindingFlags.NonPublic; + BindingFlags bindingFlags = type.IsPublic || type.IsNestedPublic ? BindingFlags.Public : BindingFlags.NonPublic; return bindingFlags; } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs index 985633d7f1a8ec..554ccc22561f36 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs @@ -414,6 +414,53 @@ public interface InterfaceDerivedFromOtherInterface : DefineMethodOverrideInterf public string M2(int a); } + [Fact] + public void DefineNestedType_GetNestedType() + { + PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyAndModule(out ModuleBuilder mb); + + // define two top level classes + TypeBuilder type1 = mb.DefineType("Type1", TypeAttributes.Public | TypeAttributes.Class); + TypeBuilder type2 = mb.DefineType("Type2", TypeAttributes.Public | TypeAttributes.Class); // used to make sure we never find that one + + // Define a public and private nested class in Type1 + TypeBuilder nestedType1 = type1.DefineNestedType("NestedType1", TypeAttributes.NestedPublic | TypeAttributes.Class); + TypeBuilder nestedType2 = type1.DefineNestedType("NestedType2", TypeAttributes.NestedPrivate | TypeAttributes.Class); + + // create all the types + nestedType2.CreateType(); + nestedType1.CreateType(); + type2.CreateType(); + type1.CreateType(); + + // Get public nested types of type1 + Type[] nestedTypes = type1.GetNestedTypes(BindingFlags.Public); + Assert.Equal(1, nestedTypes.Length); + Assert.Equal(nestedType1, nestedTypes[0]); + + // Get all nested types of type1 + nestedTypes = type1.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public); + Assert.Equal(2, nestedTypes.Length); + Assert.Contains(nestedType1, nestedTypes); + Assert.Contains(nestedType2, nestedTypes); + + // Get the nested type by name + Type? type = type1.GetNestedType("NestedType1"); + Assert.Equal(nestedType1, type); + + // Get a name that doesn't exist + type = type1.GetNestedType("NestedType3"); + Assert.Null(type); + + // Get by name with wrong flag + type = type1.GetNestedType("NestedType1", BindingFlags.NonPublic); + Assert.Null(type); + + // Type2 should not have any nested types + nestedTypes = type2.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); + Assert.Empty(nestedTypes); + } + [Fact] public void CreateType_ValidateMethods() { From 18375d77169a04787276dc0762e7ed05a24790df Mon Sep 17 00:00:00 2001 From: Pascal Arnold Date: Tue, 29 Oct 2024 23:38:28 -0400 Subject: [PATCH 4/6] Added GetMembers and GetMember --- .../System/Reflection/Emit/TypeBuilderImpl.cs | 220 +++++++++++++++++- .../AssemblySaveTypeBuilderAPIsTests.cs | 81 +++++++ 2 files changed, 295 insertions(+), 6 deletions(-) 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 d55c9f53cf758c..8ea7bf53dd20dd 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 @@ -72,7 +72,7 @@ internal TypeBuilderImpl(string fullName, TypeAttributes typeAttributes, if (interfaces != null) { - _interfaces = new List(); + _interfaces = new List(interfaces.Length); for (int i = 0; i < interfaces.Length; i++) { Type @interface = interfaces[i]; @@ -751,6 +751,24 @@ private static bool MatchesTheFilter(MethodBuilderImpl method, BindingFlags meth return true; } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + private ConstructorInfo[] GetConstructors(string name, BindingFlags bindingAttr) + { + ThrowIfNotCreated(); + ConstructorInfo[] candidates = GetConstructors(bindingAttr); + List constructors = new List(); + + foreach (ConstructorInfo ctor in candidates) + { + if (name == ctor.Name) + { + constructors.Add(ctor); + } + } + + return constructors.ToArray(); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) { @@ -775,12 +793,30 @@ public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) => throw new NotSupportedException(); + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] + private MethodInfo[] GetMethods(string name, BindingFlags bindingAttr) + { + ArgumentNullException.ThrowIfNull(name); + ThrowIfNotCreated(); + + List methods = new List(); + foreach (MethodBuilderImpl method in _methodDefinitions) + { + if (name == method.Name && MatchesTheFilter(method, GetBindingFlags(method), bindingAttr, CallingConventions.Any, method.ParameterTypes)) + { + methods.Add(method); + } + } + + return methods.ToArray(); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] public override MethodInfo[] GetMethods(BindingFlags bindingAttr) { ThrowIfNotCreated(); - List methods = new(); + List methods = new List(); foreach (MethodBuilderImpl method in _methodDefinitions) { if (!method.IsConstructor && MatchesTheFilter(method, GetBindingFlags(method), bindingAttr, CallingConventions.Any, method.ParameterTypes)) @@ -873,6 +909,25 @@ private static BindingFlags GetBindingFlags(FieldBuilderImpl field) return bindingFlags; } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] + private FieldInfo[] GetFields(string name, BindingFlags bindingAttr) + { + ArgumentNullException.ThrowIfNull(name); + ThrowIfNotCreated(); + + List candidates = new List(_fieldDefinitions.Count); + foreach (FieldBuilderImpl fieldInfo in _fieldDefinitions) + { + BindingFlags fieldFlags = GetBindingFlags(fieldInfo); + if (name == fieldInfo.Name && (bindingAttr & fieldFlags) == fieldFlags) + { + candidates.Add(fieldInfo); + } + } + + return candidates.ToArray(); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] public override FieldInfo[] GetFields(BindingFlags bindingAttr) { @@ -944,6 +999,24 @@ internal static BindingFlags GetBindingFlags(PropertyBuilderImpl property) return bindingFlags; } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] + private PropertyInfo[] GetProperties(string name, BindingFlags bindingAttr) + { + ArgumentNullException.ThrowIfNull(name); + ThrowIfNotCreated(); + List candidates = new List(_propertyDefinitions.Count); + foreach (PropertyBuilderImpl property in _propertyDefinitions) + { + BindingFlags flags = GetBindingFlags(property); + if (name == property.Name && (bindingAttr & flags) == flags) + { + candidates.Add(property); + } + } + + return candidates.ToArray(); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) { @@ -952,8 +1025,8 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) List candidates = new List(_propertyDefinitions.Count); foreach (PropertyBuilderImpl property in _propertyDefinitions) { - BindingFlags fieldFlags = GetBindingFlags(property); - if ((bindingAttr & fieldFlags) == fieldFlags) + BindingFlags flags = GetBindingFlags(property); + if ((bindingAttr & flags) == flags) { candidates.Add(property); } @@ -988,8 +1061,10 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) else { if (returnType is null) + { // if we are here we have no args or property type to select over and we have more than one property with that name throw new AmbiguousMatchException(SR.Format(SR.AmbiguousMatch_MemberInfo, firstCandidate.DeclaringType, firstCandidate.Name)); + } } } @@ -1023,10 +1098,31 @@ private static BindingFlags GetBindingFlags(TypeBuilderImpl type) return bindingFlags; } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] + private Type[] GetNestedTypes(string name, BindingFlags bindingAttr) + { + ArgumentNullException.ThrowIfNull(name); + ThrowIfNotCreated(); + + Type[] candidates = GetNestedTypes(bindingAttr); + List nestedTypes = new List(); + + foreach (Type type in candidates) + { + if (type.Name == name) + { + nestedTypes.Add(type); + } + } + + return nestedTypes.ToArray(); + } + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] public override Type[] GetNestedTypes(BindingFlags bindingAttr) { ThrowIfNotCreated(); + List nestedTypes = new List(); foreach (TypeBuilderImpl type in _module.GetNestedTypeBuilders(this)) { @@ -1043,6 +1139,8 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr) [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] public override Type? GetNestedType(string name, BindingFlags bindingAttr) { + ArgumentNullException.ThrowIfNull(name); + Type[] types = GetNestedTypes(bindingAttr); Type? match = null; @@ -1063,7 +1161,87 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr) } [DynamicallyAccessedMembers(GetAllMembers)] - public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) => throw new NotSupportedException(); + public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) + { + ArgumentNullException.ThrowIfNull(name); + + MethodInfo[] methods = []; + ConstructorInfo[] constructors = []; + PropertyInfo[] properties = []; + EventInfo[] events = []; + FieldInfo[] fields = []; + Type[] nestedTypes = []; + + int totalCount = 0; + + // Methods + if ((type & MemberTypes.Method) != 0) + { + methods = GetMethods(name, bindingAttr); + if (type == MemberTypes.Method) + return methods; + totalCount += methods.Length; + } + + // Constructors + if ((type & MemberTypes.Constructor) != 0) + { + constructors = GetConstructors(name, bindingAttr); + if (type == MemberTypes.Constructor) + return constructors; + totalCount += constructors.Length; + } + + // Properties + if ((type & MemberTypes.Property) != 0) + { + properties = GetProperties(name, bindingAttr); + if (type == MemberTypes.Property) + return properties; + totalCount += properties.Length; + } + + // Missing in TypeBuilderImpl + // Events + //if ((type & MemberTypes.Event) != 0) + //{ + // events = GetEventCandidates(name, bindingAttr, true); + // if (type == MemberTypes.Event) + // return events.ToArray(); + // totalCount += events.Count; + //} + + // Fields + if ((type & MemberTypes.Field) != 0) + { + fields = GetFields(name, bindingAttr); + if (type == MemberTypes.Field) + return fields; + totalCount += fields.Length; + } + + // NestedTypes + if ((type & (MemberTypes.NestedType | MemberTypes.TypeInfo)) != 0) + { + nestedTypes = GetNestedTypes(name, bindingAttr); + if (type == MemberTypes.NestedType || type == MemberTypes.TypeInfo) + return nestedTypes; + totalCount += nestedTypes.Length; + } + + MemberInfo[] compressMembers = (type == (MemberTypes.Method | MemberTypes.Constructor)) ? + new MethodBase[totalCount] : new MemberInfo[totalCount]; + + int i = 0; + methods.CopyTo(compressMembers, i); i += methods.Length; + constructors.CopyTo(compressMembers, i); i += constructors.Length; + properties.CopyTo(compressMembers, i); i += properties.Length; + events.CopyTo(compressMembers, i); i += events.Length; + fields.CopyTo(compressMembers, i); i += fields.Length; + nestedTypes.CopyTo(compressMembers, i); + + return compressMembers; + } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:DynamicallyAccessedMembers", Justification = "Methods are loaded from this TypeBuilder")] public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type interfaceType) @@ -1143,7 +1321,37 @@ private void ValidateInterfaceType(Type interfaceType) } [DynamicallyAccessedMembers(GetAllMembers)] - public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotSupportedException(); + public override MemberInfo[] GetMembers(BindingFlags bindingAttr) + { + ThrowIfNotCreated(); + + MethodInfo[] methods = GetMethods(bindingAttr); + ConstructorInfo[] constructors = GetConstructors(bindingAttr); + PropertyInfo[] properties = GetProperties(bindingAttr); + // EventInfo[] events = GetEvents(bindingAttr); // missing in TypeBuilderImpl + FieldInfo[] fields = GetFields(bindingAttr); + Type[] nestedTypes = GetNestedTypes(bindingAttr); + + // Interfaces are excluded from the result of GetMembers + + MemberInfo[] members = new MemberInfo[ + methods.Length + + constructors.Length + + properties.Length + + // events.Length + + fields.Length + + nestedTypes.Length]; + + int i = 0; + methods.CopyTo(members, i); i += methods.Length; + constructors.CopyTo(members, i); i += constructors.Length; + properties.CopyTo(members, i); i += properties.Length; + //events.CopyTo(members, i); i += events.Length; + fields.CopyTo(members, i); i += fields.Length; + nestedTypes.CopyTo(members, i); + + return members; + } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "The GetInterfaces technically requires all interfaces to be preserved" + diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs index 554ccc22561f36..74ff0f0fd50d6d 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs @@ -461,6 +461,87 @@ public void DefineNestedType_GetNestedType() Assert.Empty(nestedTypes); } + [Fact] + public void CreateType_GetMembers() + { + AssemblySaveTools.PopulateAssemblyAndModule(out ModuleBuilder mb); + + TypeBuilder type = mb.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); + + // Define a class with a field, method, property, constructor and nested type + FieldBuilder field = type.DefineField("Field", typeof(int), FieldAttributes.Public); + + MethodBuilder method = type.DefineMethod("Method", MethodAttributes.Public, typeof(int), Type.EmptyTypes); + ILGenerator ilGenerator = method.GetILGenerator(); + ilGenerator.Emit(OpCodes.Ldc_I4_1); + ilGenerator.Emit(OpCodes.Ret); + + PropertyBuilder property = type.DefineProperty("Property", PropertyAttributes.None, typeof(int), Type.EmptyTypes); + MethodBuilder getMethod = type.DefineMethod("get_Property", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(int), Type.EmptyTypes); + ILGenerator getIlGenerator = getMethod.GetILGenerator(); + getIlGenerator.Emit(OpCodes.Ldc_I4_2); + getIlGenerator.Emit(OpCodes.Ret); + property.SetGetMethod(getMethod); + + ConstructorBuilder constructor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); + ILGenerator constructorIlGenerator = constructor.GetILGenerator(); + constructorIlGenerator.Emit(OpCodes.Ret); + + TypeBuilder nestedType = type.DefineNestedType("NestedType", TypeAttributes.NestedPublic | TypeAttributes.Class); + + // Create a child type + TypeBuilder child = mb.DefineType("ChildType", TypeAttributes.Public | TypeAttributes.Class, type); + + nestedType.CreateType(); + type.CreateType(); + child.CreateType(); + + Test(type); + Test(child); + + void Test(TypeBuilder type) + { + // Test get all + MemberInfo[] members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance); + Assert.Contains(field, members); + Assert.Contains(method, members); + Assert.Contains(property, members); + Assert.Contains(getMethod, members); + Assert.Contains(constructor, members); + Assert.Contains(nestedType, members); + + // Test get all with wrong flags + members = type.GetMembers(BindingFlags.NonPublic); + Assert.Empty(members); + + // Test get field by name + members = type.GetMember("Field", MemberTypes.Field, BindingFlags.Public | BindingFlags.Instance); + Assert.Single(members); + Assert.Equal(field, members[0]); + + // Test get method by name + members = type.GetMember("Method", MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance); + Assert.Single(members); + Assert.Equal(method, members[0]); + + // Test get property by name + members = type.GetMember("Property", MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance); + Assert.Single(members); + Assert.Equal(property, members[0]); + + // Test get constructor by name + members = type.GetMember(".ctor", MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance); + Assert.Single(members); + Assert.Equal(constructor, members[0]); + + // Test get nested type by name + members = type.GetMember("NestedType", MemberTypes.NestedType, BindingFlags.Public); + Assert.Single(members); + Assert.Equal(nestedType, members[0]); + } + } + + [Fact] public void CreateType_ValidateMethods() { From f1112231004579347c923e9a334c57dfc674bdbc Mon Sep 17 00:00:00 2001 From: Pascal Arnold Date: Tue, 29 Oct 2024 23:58:22 -0400 Subject: [PATCH 5/6] Bugfix GetMethods, GetFields, GetProperties not returning parent members --- .../System/Reflection/Emit/TypeBuilderImpl.cs | 51 +++++++++++-------- .../AssemblySaveTypeBuilderAPIsTests.cs | 36 +++++++------ 2 files changed, 52 insertions(+), 35 deletions(-) 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 8ea7bf53dd20dd..2ae0e6c4b27ae6 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 @@ -797,12 +797,12 @@ public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) private MethodInfo[] GetMethods(string name, BindingFlags bindingAttr) { ArgumentNullException.ThrowIfNull(name); - ThrowIfNotCreated(); + MethodInfo[] candidates = GetMethods(bindingAttr); List methods = new List(); - foreach (MethodBuilderImpl method in _methodDefinitions) + foreach (MethodInfo method in candidates) { - if (name == method.Name && MatchesTheFilter(method, GetBindingFlags(method), bindingAttr, CallingConventions.Any, method.ParameterTypes)) + if (name == method.Name) { methods.Add(method); } @@ -915,17 +915,18 @@ private FieldInfo[] GetFields(string name, BindingFlags bindingAttr) ArgumentNullException.ThrowIfNull(name); ThrowIfNotCreated(); - List candidates = new List(_fieldDefinitions.Count); - foreach (FieldBuilderImpl fieldInfo in _fieldDefinitions) + FieldInfo[] candidates = GetFields(bindingAttr); + List fields = new List(); + + foreach (FieldInfo field in candidates) { - BindingFlags fieldFlags = GetBindingFlags(fieldInfo); - if (name == fieldInfo.Name && (bindingAttr & fieldFlags) == fieldFlags) + if (name == field.Name) { - candidates.Add(fieldInfo); + fields.Add(field); } } - return candidates.ToArray(); + return fields.ToArray(); } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] @@ -933,17 +934,22 @@ public override FieldInfo[] GetFields(BindingFlags bindingAttr) { ThrowIfNotCreated(); - List candidates = new List(_fieldDefinitions.Count); + List fields = new List(_fieldDefinitions.Count); foreach (FieldBuilderImpl fieldInfo in _fieldDefinitions) { BindingFlags fieldFlags = GetBindingFlags(fieldInfo); if ((bindingAttr & fieldFlags) == fieldFlags) { - candidates.Add(fieldInfo); + fields.Add(fieldInfo); } } - return candidates.ToArray(); + if (!bindingAttr.HasFlag(BindingFlags.DeclaredOnly) && _typeParent != null) + { + fields.AddRange(_typeParent.GetFields(bindingAttr)); + } + + return fields.ToArray(); } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063:UnrecognizedReflectionPattern")] @@ -1003,18 +1009,18 @@ internal static BindingFlags GetBindingFlags(PropertyBuilderImpl property) private PropertyInfo[] GetProperties(string name, BindingFlags bindingAttr) { ArgumentNullException.ThrowIfNull(name); - ThrowIfNotCreated(); - List candidates = new List(_propertyDefinitions.Count); - foreach (PropertyBuilderImpl property in _propertyDefinitions) + + PropertyInfo[] candidates = GetProperties(bindingAttr); + List properties = new List(); + foreach (PropertyInfo property in candidates) { - BindingFlags flags = GetBindingFlags(property); - if (name == property.Name && (bindingAttr & flags) == flags) + if (name == property.Name) { - candidates.Add(property); + properties.Add(property); } } - return candidates.ToArray(); + return properties.ToArray(); } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] @@ -1022,7 +1028,7 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) { ThrowIfNotCreated(); - List candidates = new List(_propertyDefinitions.Count); + List candidates = new List(_propertyDefinitions.Count); foreach (PropertyBuilderImpl property in _propertyDefinitions) { BindingFlags flags = GetBindingFlags(property); @@ -1032,6 +1038,11 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) } } + if (!bindingAttr.HasFlag(BindingFlags.DeclaredOnly) && _typeParent != null) + { + candidates.AddRange(_typeParent.GetProperties(bindingAttr)); + } + return candidates.ToArray(); } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs index 74ff0f0fd50d6d..9cf05f68a6f71e 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs @@ -234,7 +234,7 @@ public void TypeBuilderImplementsGenericInterfaceWithTypeBuilderGenericConstrain TypeBuilder ifaceType = module.DefineType("InterfaceType", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract); TypeBuilder implType = module.DefineType("ImplType", TypeAttributes.Public); - GenericTypeParameterBuilder[] gParams = implType.DefineGenericParameters("T"); + GenericTypeParameterBuilder[] gParams = implType.DefineGenericParameters("T"); gParams[0].SetInterfaceConstraints(ifaceType); Type constructedGenericInterface = typeof(IComparable<>).MakeGenericType(gParams); implType.AddInterfaceImplementation(constructedGenericInterface); @@ -507,8 +507,11 @@ void Test(TypeBuilder type) Assert.Contains(method, members); Assert.Contains(property, members); Assert.Contains(getMethod, members); - Assert.Contains(constructor, members); - Assert.Contains(nestedType, members); + if (type != child) // child type doesn't have the parent constructor nor the nested type + { + Assert.Contains(nestedType, members); + Assert.Contains(constructor, members); + } // Test get all with wrong flags members = type.GetMembers(BindingFlags.NonPublic); @@ -529,15 +532,18 @@ void Test(TypeBuilder type) Assert.Single(members); Assert.Equal(property, members[0]); - // Test get constructor by name - members = type.GetMember(".ctor", MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance); - Assert.Single(members); - Assert.Equal(constructor, members[0]); - - // Test get nested type by name - members = type.GetMember("NestedType", MemberTypes.NestedType, BindingFlags.Public); - Assert.Single(members); - Assert.Equal(nestedType, members[0]); + if (type != child) + { + // Test get constructor by name + members = type.GetMember(".ctor", MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance); + Assert.Single(members); + Assert.Equal(constructor, members[0]); + + // Test get nested type by name + members = type.GetMember("NestedType", MemberTypes.NestedType, BindingFlags.Public); + Assert.Single(members); + Assert.Equal(nestedType, members[0]); + } } } @@ -553,7 +559,7 @@ public void CreateType_ValidateMethods() TypeBuilder abstractType = module.DefineType("AbstractType", TypeAttributes.Public | TypeAttributes.Abstract); MethodBuilder abstractMethod = abstractType.DefineMethod("AbstractMethod", MethodAttributes.Public | MethodAttributes.Abstract); abstractType.DefineMethod("PinvokeMethod", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.PinvokeImpl); - Assert.Throws(() => abstractMethod.GetILGenerator()); + Assert.Throws(() => abstractMethod.GetILGenerator()); abstractType.CreateType(); // succeeds TypeBuilder concreteTypeWithNativeAndPinvokeMethod = module.DefineType("Type3", TypeAttributes.Public); @@ -935,7 +941,7 @@ public static void DefineUninitializedDataTest() public void GetFieldGetFieldsTest() { AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); - foreach(object[] fd in FieldTestData) + foreach (object[] fd in FieldTestData) { FieldBuilder field = type.DefineField((string)fd[0], (Type)fd[1], (FieldAttributes)fd[2]); Assert.Equal(fd[0], field.Name); @@ -956,7 +962,7 @@ public void GetFieldGetFieldsTest() Assert.Throws(() => type.GetField("TestName1", Helpers.AllFlags)); Assert.Equal(allFields[0], type.GetField("TestName1", BindingFlags.Public | BindingFlags.Instance)); - Assert.Equal(allFields[allFields.Length-1], type.GetField("TestName1", BindingFlags.Public | BindingFlags.Static)); + Assert.Equal(allFields[allFields.Length - 1], type.GetField("TestName1", BindingFlags.Public | BindingFlags.Static)); Assert.Equal(allFields[10], type.GetField("testname5", Helpers.AllFlags)); Assert.Equal(allFields[10], type.GetField("testname5", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)); Assert.Equal(allFields[9], type.GetField("testname5", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase)); From fa60b1be53e5a3d5ce848c4f41040f05a91259b5 Mon Sep 17 00:00:00 2001 From: snakex64 Date: Wed, 30 Oct 2024 00:21:21 -0400 Subject: [PATCH 6/6] Bugfix GetInterfaces not returning parent class interfaces --- .../src/System/Reflection/Emit/TypeBuilderImpl.cs | 14 +++++++++++++- 1 file changed, 13 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 2ae0e6c4b27ae6..1ccd44ae872dac 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 @@ -984,7 +984,19 @@ public override FieldInfo[] GetFields(BindingFlags bindingAttr) } [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] - public override Type[] GetInterfaces() => _interfaces == null ? EmptyTypes : _interfaces.ToArray(); + public override Type[] GetInterfaces() + { + ThrowIfNotCreated(); + + List interfaces = _interfaces ?? []; + + if(_typeParent != null) + { + interfaces.AddRange(_typeParent.GetInterfaces()); + } + + return interfaces.ToArray(); + } internal static BindingFlags GetBindingFlags(PropertyBuilderImpl property) {