Skip to content

Commit

Permalink
Add EnumBuilder implementation and other changes (#88503)
Browse files Browse the repository at this point in the history
* Add EnumBuilder implementation and other changes

* Update src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/EnumBuilderImpl.cs

Co-authored-by: Jan Kotas <[email protected]>

* Apply feedback

---------

Co-authored-by: Jan Kotas <[email protected]>
  • Loading branch information
buyaa-n and jkotas authored Jul 13, 2023
1 parent 563a549 commit 3eb6eef
Show file tree
Hide file tree
Showing 16 changed files with 894 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,35 +292,6 @@ public override bool IsDefined(Type attributeType, bool inherit)
return m_typeBuilder.IsDefined(attributeType, inherit);
}

/*****************************************************
*
* private/protected functions
*
*/

public override Type MakePointerType()
{
return SymbolType.FormCompoundType("*", this, 0)!;
}

public override Type MakeByRefType()
{
return SymbolType.FormCompoundType("&", this, 0)!;
}

[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
public override Type MakeArrayType()
{
return SymbolType.FormCompoundType("[]", this, 0)!;
}

[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
public override Type MakeArrayType(int rank)
{
string s = GetRankString(rank);
return SymbolType.FormCompoundType(s, this, 0)!;
}

// Constructs a EnumBuilder.
// EnumBuilder can only be a top-level (not nested) enum type.
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2064:UnrecognizedReflectionPattern",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,28 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)

public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
=> SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);

public override Type MakePointerType()
{
return SymbolType.FormCompoundType("*", this, 0)!;
}

public override Type MakeByRefType()
{
return SymbolType.FormCompoundType("&", this, 0)!;
}

[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
public override Type MakeArrayType()
{
return SymbolType.FormCompoundType("[]", this, 0)!;
}

[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
public override Type MakeArrayType(int rank)
{
string s = GetRankString(rank);
return SymbolType.FormCompoundType(s, this, 0)!;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj", "{772C93D4-FC45-46AA-B09F-26F01B672EDC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{E5543842-139D-43BD-B604-E65EBB91649E}"
Expand Down Expand Up @@ -596,4 +596,4 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {739AA767-154B-4C69-8C9B-C3D332833D92}
EndGlobalSection
EndGlobal
EndGlobal
12 changes: 12 additions & 0 deletions src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,16 @@
<data name="InvalidOperation_GenericParametersAlreadySet" xml:space="preserve">
<value>The generic parameters are already defined on this MethodBuilder.</value>
</data>
<data name="Argument_ShouldOnlySetVisibilityFlags" xml:space="preserve">
<value>Should only set visibility flags when creating EnumBuilder.</value>
</data>
<data name="Argument_ConstantDoesntMatch" xml:space="preserve">
<value>Constant does not match the defined type.</value>
</data>
<data name="Argument_ConstantNull" xml:space="preserve">
<value>Null is not a valid constant value for this type.</value>
</data>
<data name="InvalidOperation_NoUnderlyingTypeOnEnum" xml:space="preserve">
<value>Underlying type information on enumeration is not specified.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
<ItemGroup>
<Compile Include="System\Reflection\Emit\CustomAttributeWrapper.cs" />
<Compile Include="System\Reflection\Emit\AssemblyBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\EnumBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\FieldBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\GenericTypeParameterBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\MethodBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\ModuleBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\ParameterBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\PseudoCustomAttributesData.cs" />
<Compile Include="System\Reflection\Emit\TypeBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\SignatureHelper.cs" />
<Compile Include="System\Reflection\Emit\TypeBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\TypeNameBuilder.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CoreLibProject)" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;

namespace System.Reflection.Emit
{
internal sealed class EnumBuilderImpl : EnumBuilder
{
private readonly FieldBuilder _underlyingField;
internal readonly TypeBuilderImpl _typeBuilder;

internal EnumBuilderImpl(string name, Type underlyingType, TypeAttributes visibility, ModuleBuilderImpl module, TypeDefinitionHandle typeHandle)
{
if ((visibility & ~TypeAttributes.VisibilityMask) != 0)
throw new ArgumentException(SR.Argument_ShouldOnlySetVisibilityFlags, nameof(name));

_typeBuilder = new TypeBuilderImpl(name, visibility | TypeAttributes.Sealed, typeof(Enum), module, typeHandle, null, PackingSize.Unspecified, TypeBuilder.UnspecifiedTypeSize, null);

// Define the underlying field for the enum. It will be a non-static, private field with special name bit set.
_underlyingField = _typeBuilder.DefineField("value__", underlyingType, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
}

protected override FieldBuilder UnderlyingFieldCore => _underlyingField;

[return: DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))]
protected override TypeInfo CreateTypeInfoCore() => _typeBuilder.CreateTypeInfo();

protected override FieldBuilder DefineLiteralCore(string literalName, object? literalValue)
{
FieldBuilder fieldBuilder = _typeBuilder.DefineField(
literalName,
_typeBuilder,
FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal);
fieldBuilder.SetConstant(literalValue);
return fieldBuilder;
}

protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute) =>
_typeBuilder.SetCustomAttribute(con, binaryAttribute);

public override Guid GUID => _typeBuilder.GUID;

public override string Name => _typeBuilder.Name;

public override Module Module => _typeBuilder.Module;

public override Assembly Assembly => _typeBuilder.Assembly;

public override RuntimeTypeHandle TypeHandle => _typeBuilder.TypeHandle;

public override string? FullName => _typeBuilder.FullName;

public override string? AssemblyQualifiedName => _typeBuilder.AssemblyQualifiedName;

public override string? Namespace => _typeBuilder.Namespace;

public override Type? BaseType => _typeBuilder.BaseType;

public override bool IsByRefLike => false;

public override bool IsTypeDefinition => true;

public override bool IsSZArray => false;

public override bool IsConstructedGenericType => false;

public override Type? DeclaringType => _typeBuilder.DeclaringType;

public override Type? ReflectedType => _typeBuilder.ReflectedType;

public override Type UnderlyingSystemType => GetEnumUnderlyingType();

public override Type GetEnumUnderlyingType() => _underlyingField.FieldType;

protected override bool IsArrayImpl() => false;

protected override bool IsPrimitiveImpl() => false;

protected override bool IsValueTypeImpl() => true;

protected override bool IsByRefImpl() => false;

protected override bool IsPointerImpl() => false;

protected override bool IsCOMObjectImpl() => false;

public override Type? GetElementType() => _typeBuilder.GetElementType();

protected override bool HasElementTypeImpl() => _typeBuilder.HasElementType;

protected override TypeAttributes GetAttributeFlagsImpl() => _typeBuilder.Attributes;

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
public override Type[] GetInterfaces() => EmptyTypes;

public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException();
public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException();
public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public override object? InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target,
object?[]? args, ParameterModifier[]? modifiers, Globalization.CultureInfo? culture, string[]? namedParameters) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder,
CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents)]
public override EventInfo[] GetEvents() => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
public override EventInfo[] GetEvents(BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
protected override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder,
CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public override FieldInfo? GetField(string name, BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public override FieldInfo[] GetFields(BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
public override Type? GetInterface(string name, bool ignoreCase) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder,
Type? returnType, Type[]? types, ParameterModifier[]? modifiers) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type? GetNestedType(string name, BindingFlags bindingAttr) => throw new NotSupportedException();
[DynamicallyAccessedMembers(TypeBuilderImpl.GetAllMembers)]
public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) => throw new NotSupportedException();
public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type interfaceType)
=> throw new NotSupportedException();
[DynamicallyAccessedMembers(TypeBuilderImpl.GetAllMembers)]
public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotSupportedException();
public override bool IsAssignableFrom([NotNullWhen(true)] Type? c) => throw new NotSupportedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal sealed class FieldBuilderImpl : FieldBuilder
internal MarshallingData? _marshallingData;
internal int _offset;
internal List<CustomAttributeWrapper>? _customAttributes;
internal object? _defaultValue = DBNull.Value;

internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes)
{
Expand All @@ -32,7 +33,61 @@ internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type ty
_offset = -1;
}

protected override void SetConstantCore(object? defaultValue) => throw new NotImplementedException();
protected override void SetConstantCore(object? defaultValue)
{
if (defaultValue == null)
{
// nullable value types can hold null value.
if (_fieldType.IsValueType && !(_fieldType.IsGenericType && _fieldType.GetGenericTypeDefinition() == typeof(Nullable<>)))
throw new ArgumentException(SR.Argument_ConstantNull);
}
else
{
Type type = defaultValue.GetType();
Type destType = _fieldType;

// We should allow setting a constant value on a ByRef parameter
if (destType.IsByRef)
destType = destType.GetElementType()!;

// Convert nullable types to their underlying type.
destType = Nullable.GetUnderlyingType(destType) ?? destType;

if (destType.IsEnum)
{
Type underlyingType;
if (destType is EnumBuilderImpl enumBldr)
{
underlyingType = enumBldr.GetEnumUnderlyingType();

if (type != enumBldr._typeBuilder.UnderlyingSystemType && type != underlyingType)
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
else if (destType is TypeBuilderImpl typeBldr)
{
underlyingType = typeBldr.UnderlyingSystemType;

if (underlyingType == null || (type != typeBldr.UnderlyingSystemType && type != underlyingType))
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
else
{
underlyingType = Enum.GetUnderlyingType(destType);

if (type != destType && type != underlyingType)
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
}
else
{
if (!destType.IsAssignableFrom(type))
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}

_defaultValue = defaultValue;
}
}

protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
// Handle pseudo custom attributes
Expand Down
Loading

0 comments on commit 3eb6eef

Please sign in to comment.