Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EnumBuilder implementation and other changes #88503

Merged
merged 4 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we need the differentiation here - the one above may be acceptable for null as well, plus considering there is only one case for the null check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the above acceptable, but it might be cleared than the above, also the exception messages and throwing logic copied from corelib, it might be better to be consistent with corelib messaging, let me know if you think otherwise.

<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" />
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
</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