{
public class CustomAttributeBuilder
{
- internal readonly ConstructorInfo m_con;
+ private readonly ConstructorInfo m_con;
private readonly object?[] m_constructorArgs;
private readonly byte[] m_blob;
+ internal ConstructorInfo Ctor => m_con;
+
+ internal byte[] Data => m_blob;
+
// public constructor to form the custom attribute with constructor and constructor
// parameters.
public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs) :
/// <summary>
/// Use this function if client decides to form the custom attribute blob themselves.
/// </summary>
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
lock (SyncRoot)
{
binaryAttribute);
}
}
-
- /// <summary>
- /// Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder.
- /// </summary>
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- lock (SyncRoot)
- {
- customBuilder.CreateCustomAttribute(_manifestModuleBuilder, AssemblyDefToken);
- }
- }
}
}
return m_methodBuilder.ReturnType;
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
m_methodBuilder.SetCustomAttribute(con, binaryAttribute);
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- m_methodBuilder.SetCustomAttribute(customBuilder);
- }
-
protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
{
m_methodBuilder.SetImplementationFlags(attributes);
}
// Use this function if client decides to form the custom attribute blob themselves
-
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
m_typeBuilder.SetCustomAttribute(con, binaryAttribute);
}
- // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- m_typeBuilder.SetCustomAttribute(customBuilder);
- }
-
// Return the class that declared this Field.
public override Type? DeclaringType => m_typeBuilder.DeclaringType;
public override Type? ReflectedType => m_typeBuilder.ReflectedType;
-
// Returns true if one or more instance of attributeType is defined on this member.
public override bool IsDefined(Type attributeType, bool inherit)
{
return SymbolType.FormCompoundType(s, this, 0)!;
}
-
// Constructs a EnumBuilder.
// EnumBuilder can only be a top-level (not nested) enum type.
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2064:UnrecognizedReflectionPattern",
// Use this function if client decides to form the custom attribute blob themselves
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
m_type.ThrowIfCreated();
binaryAttribute);
}
- // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- m_type.ThrowIfCreated();
- customBuilder.CreateCustomAttribute(m_module, m_evToken);
- }
-
private readonly string m_name; // The name of the event
private readonly int m_evToken; // The token of this event
private readonly RuntimeModuleBuilder m_module;
RuntimeTypeBuilder.SetConstantValue(m_typeBuilder.GetModuleBuilder(), m_fieldTok, m_fieldType, defaultValue);
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
RuntimeModuleBuilder moduleBuilder = (RuntimeModuleBuilder)m_typeBuilder.Module;
m_fieldTok, moduleBuilder.GetMethodMetadataToken(con), binaryAttribute);
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- m_typeBuilder.ThrowIfCreated();
-
- customBuilder.CreateCustomAttribute((RuntimeModuleBuilder)m_typeBuilder.Module, m_fieldTok);
- }
-
#endregion
}
}
#endregion
#region Protected Members Overrides
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
m_type.SetGenParamCustomAttribute(con, binaryAttribute);
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- m_type.SetGenParamCustomAttribute(customBuilder);
- }
-
protected override void SetBaseTypeConstraintCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint)
{
m_type.SetParent(baseTypeConstraint);
return GetModuleBuilder();
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
ThrowIfGeneric();
RuntimeTypeBuilder.DefineCustomAttribute(m_module, MetadataToken,
ParseCA(con);
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- ThrowIfGeneric();
- customBuilder.CreateCustomAttribute(m_module, MetadataToken);
-
- if (IsKnownCA(customBuilder.m_con))
- ParseCA(customBuilder.m_con);
- }
-
// this method should return true for any and every ca that requires more work
// than just setting the ca
private static bool IsKnownCA(ConstructorInfo con)
#region Other
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
RuntimeTypeBuilder.DefineCustomAttribute(
this,
binaryAttribute);
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- customBuilder.CreateCustomAttribute(this, 1); // This is hard coding the module token to 1
- }
-
#endregion
#endregion
}
// Use this function if client decides to form the custom attribute blob themselves
-
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
m_containingType.ThrowIfCreated();
RuntimeTypeBuilder.DefineCustomAttribute(
binaryAttribute);
}
- // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
- {
- m_containingType.ThrowIfCreated();
- customBuilder.CreateCustomAttribute(m_moduleBuilder, m_tkProperty);
- }
-
// Not supported functions in dynamic module.
public override object GetValue(object? obj, object?[]? index)
{
private readonly byte[]? m_binaryAttribute;
private readonly CustomAttributeBuilder? m_customBuilder;
- public CustAttr(ConstructorInfo con, byte[] binaryAttribute)
+ public CustAttr(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
ArgumentNullException.ThrowIfNull(con);
- ArgumentNullException.ThrowIfNull(binaryAttribute);
m_con = con;
- m_binaryAttribute = binaryAttribute;
+ m_binaryAttribute = binaryAttribute.ToArray();
}
public CustAttr(CustomAttributeBuilder customBuilder)
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineCustomAttribute")]
private static partial void DefineCustomAttribute(QCallModule module, int tkAssociate, int tkConstructor,
- byte[]? attr, int attrLength);
+ ReadOnlySpan<byte> attr, int attrLength);
internal static void DefineCustomAttribute(RuntimeModuleBuilder module, int tkAssociate, int tkConstructor,
- byte[]? attr)
+ ReadOnlySpan<byte> attr)
{
- byte[]? localAttr = null;
-
- if (attr != null)
- {
- localAttr = new byte[attr.Length];
- Buffer.BlockCopy(attr, 0, localAttr, 0, attr.Length);
- }
-
DefineCustomAttribute(new QCallModule(ref module), tkAssociate, tkConstructor,
- localAttr, (localAttr != null) ? localAttr.Length : 0);
+ attr, attr.Length);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineProperty", StringMarshalling = StringMarshalling.Utf16)]
m_genParamAttributes = genericParameterAttributes;
}
- internal void SetGenParamCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
+ internal void SetGenParamCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
CustAttr ca = new CustAttr(con, binaryAttribute);
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
+ internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
- DefineCustomAttribute(m_module, m_tdType, m_module.GetMethodMetadataToken(con), binaryAttribute);
+ SetCustomAttributeCore(con, binaryAttribute);
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
- customBuilder.CreateCustomAttribute(m_module, m_tdType);
+ DefineCustomAttribute(m_module, m_tdType, m_module.GetMethodMetadataToken(con), binaryAttribute);
}
#endregion
{
ReflectionEmitThrower.ThrowPlatformNotSupportedException();
}
+
+#pragma warning disable CA1822 // Member 'Ctor' does not access instance data and can be marked as static
+ internal ConstructorInfo Ctor => default;
+ internal byte[] Data => default;
+#pragma warning restore CA1822
}
}
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
[System.ObsoleteAttribute("Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead.", DiagnosticId = "SYSLIB0012", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
[RequiresAssemblyFiles(ThrowingMessageInRAF)]
public override string? CodeBase => throw new NotSupportedException(SR.NotSupported_DynamicAssembly);
protected abstract ILGenerator GetILGeneratorCore(int streamSize);
public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
- => SetCustomAttributeCore(con, binaryAttribute);
+ {
+ ArgumentNullException.ThrowIfNull(con);
+ ArgumentNullException.ThrowIfNull(binaryAttribute);
+
+ SetCustomAttributeCore(con, binaryAttribute);
+ }
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
- => SetCustomAttributeCore(customBuilder);
+ {
+ ArgumentNullException.ThrowIfNull(customBuilder);
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
+ }
public void SetImplementationFlags(MethodImplAttributes attributes)
=> SetImplementationFlagsCore(attributes);
public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
=> SetCustomAttributeCore(con, binaryAttribute);
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
- => SetCustomAttributeCore(customBuilder);
-
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
+ => SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
}
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
public void SetRaiseMethod(MethodBuilder mdBuilder)
=> SetRaiseMethodCore(mdBuilder);
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
public void SetOffset(int iOffset)
=> SetOffsetCore(iOffset);
public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) => SetCustomAttributeCore(con, binaryAttribute);
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
public void SetBaseTypeConstraint([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint) => SetBaseTypeConstraintCore(baseTypeConstraint);
protected abstract void SetBaseTypeConstraintCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint);
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ SetCustomAttributeCore(con, binaryAttribute);
+ }
+
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
public void SetImplementationFlags(MethodImplAttributes attributes) => SetImplementationFlagsCore(attributes);
protected abstract void SetImplementationFlagsCore(MethodImplAttributes attributes);
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
public abstract int GetTypeMetadataToken(Type type);
public abstract int GetFieldMetadataToken(FieldInfo field);
public abstract int GetMethodMetadataToken(MethodInfo method);
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
- }
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
+ }
public void SetGetMethod(MethodBuilder mdBuilder)
=> SetGetMethodCore(mdBuilder);
SetCustomAttributeCore(con, binaryAttribute);
}
- protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute);
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
- SetCustomAttributeCore(customBuilder);
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
- protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
-
public void SetParent([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent)
=> SetParentCore(parent);
public override System.Type? GetType(string name, bool throwOnError, bool ignoreCase) { throw null; }
public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
}
[System.FlagsAttribute]
public enum AssemblyBuilderAccess
public override object Invoke(System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder? binder, object?[]? parameters, System.Globalization.CultureInfo? culture) { throw null; }
public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetImplementationFlags(System.Reflection.MethodImplAttributes attributes) { }
protected abstract void SetImplementationFlagsCore(System.Reflection.MethodImplAttributes attributes);
public override string ToString() { throw null; }
public override System.Type MakeByRefType() { throw null; }
public override System.Type MakePointerType() { throw null; }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
}
public abstract partial class EventBuilder
{
public void SetAddOnMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { }
protected abstract void SetAddOnMethodCore(System.Reflection.Emit.MethodBuilder mdBuilder);
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetRaiseMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { }
protected abstract void SetRaiseMethodCore(System.Reflection.Emit.MethodBuilder mdBuilder);
public void SetRemoveOnMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { }
public void SetConstant(object? defaultValue) { }
protected abstract void SetConstantCore(object? defaultValue);
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetOffset(int iOffset) { }
protected abstract void SetOffsetCore(int iOffset);
public override void SetValue(object? obj, object? val, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder? binder, System.Globalization.CultureInfo? culture) { }
public void SetBaseTypeConstraint([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type? baseTypeConstraint) { }
protected abstract void SetBaseTypeConstraintCore([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint);
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetGenericParameterAttributes(System.Reflection.GenericParameterAttributes genericParameterAttributes) { }
protected abstract void SetGenericParameterAttributesCore(System.Reflection.GenericParameterAttributes genericParameterAttributes);
public void SetInterfaceConstraints(params System.Type[]? interfaceConstraints) { }
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override System.Reflection.MethodInfo MakeGenericMethod(params System.Type[] typeArguments) { throw null; }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetImplementationFlags(System.Reflection.MethodImplAttributes attributes) { }
protected abstract void SetImplementationFlagsCore(System.Reflection.MethodImplAttributes attributes);
public void SetParameters(params System.Type[] parameterTypes) { }
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Trimming changes metadata tokens")]
public override System.Type ResolveType(int metadataToken, System.Type[]? genericTypeArguments, System.Type[]? genericMethodArguments) { throw null; }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
}
public abstract partial class PropertyBuilder : System.Reflection.PropertyInfo
{
public void SetConstant(object? defaultValue) { }
protected abstract void SetConstantCore(object? defaultValue);
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetGetMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { }
protected abstract void SetGetMethodCore(System.Reflection.Emit.MethodBuilder mdBuilder);
public void SetSetMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { }
public override System.Type MakeGenericType(params System.Type[] typeArguments) { throw null; }
public override System.Type MakePointerType() { throw null; }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute);
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
- protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder);
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan<byte> binaryAttribute);
public void SetParent([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type? parent) { }
protected abstract void SetParentCore([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type? parent);
public override string ToString() { throw null; }
<data name="NotSupported_DynamicModule" xml:space="preserve">
<value>The invoked member is not supported in a dynamic module.</value>
</data>
- <data name="Argument_InvalidName" xml:space="preserve">
- <value>Invalid name.</value>
+ <data name="Argument_InvalidTypeArgument" xml:space="preserve">
+ <value>The type code may not be used as a type argument of a custom attribute .</value>
+ </data>
+ <data name="InvalidOperation_EmptyFieldForCustomAttribute" xml:space="preserve">
+ <value>Custom attribute '{0}' doesn't contain a field named '{1}'.</value>
+ </data>
+ <data name="Argument_InvalidCustomAttributeLength" xml:space="preserve">
+ <value>Custom attribute '{0}' data length is only '{1}'.</value>
+ </data>
+ <data name="Argument_InvalidProlog" xml:space="preserve">
+ <value>Custom attribute '{0}' prolog invalid.</value>
+ </data>
+ <data name="Argument_UnknownNamedType" xml:space="preserve">
+ <value>Custom attribute '{0}' has unknown named type '{1}'.</value>
+ </data>
+ <data name="NotImplemented_TypeForValue" xml:space="preserve">
+ <value>Type '{0}' not handled in the custom attribute value decoder.</value>
+ </data>
+ <data name="Argument_DllNameCannotBeEmpty" xml:space="preserve">
+ <value>DllName cannot be empty.</value>
</data>
</root>
\ No newline at end of file
<ContractTypesPartiallyMoved>true</ContractTypesPartiallyMoved>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="System\Reflection\Emit\CustomAttributeWrapper.cs" />
<Compile Include="System\Reflection\Emit\AssemblyBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\FieldBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\MethodBuilderImpl.cs" />
private ModuleBuilderImpl? _module;
private bool _previouslySaved;
+ internal List<CustomAttributeWrapper>? _customAttributes;
+
internal AssemblyBuilderImpl(AssemblyName name, Assembly coreAssembly, IEnumerable<CustomAttributeBuilder>? assemblyAttributes)
{
ArgumentNullException.ThrowIfNull(name);
}
// Add assembly metadata
- _metadataBuilder.AddAssembly(
+ AssemblyDefinitionHandle assemblyHandle = _metadataBuilder.AddAssembly(
_metadataBuilder.GetOrAddString(value: _assemblyName.Name!),
version: _assemblyName.Version ?? new Version(0, 0, 0, 0),
culture: _assemblyName.CultureName == null ? default : _metadataBuilder.GetOrAddString(value: _assemblyName.CultureName),
#pragma warning restore SYSLIB0037
);
+ _module.WriteCustomAttributes(_customAttributes, assemblyHandle);
// Add module's metadata
_module.AppendMetadata();
return null;
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException();
-
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException();
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ _customAttributes ??= new List<CustomAttributeWrapper>();
+ _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
+ }
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection.Metadata;
+
+namespace System.Reflection.Emit
+{
+ internal readonly struct CustomAttributeWrapper
+ {
+ private readonly ConstructorInfo _constructorInfo;
+ private readonly byte[] _binaryAttribute;
+
+ public CustomAttributeWrapper(ConstructorInfo constructorInfo, ReadOnlySpan<byte> binaryAttribute)
+ {
+ _constructorInfo = constructorInfo;
+ _binaryAttribute = binaryAttribute.ToArray(); // TODO: Update to BlobHandle when public API public APi for MetadataBuilder.GetOrAddBlob(ReadOnlySpan<byte>) added
+ }
+
+ public ConstructorInfo Ctor => _constructorInfo;
+ public byte[] Data => _binaryAttribute;
+ }
+
+ internal struct CustomAttributeInfo
+ {
+ public ConstructorInfo _ctor;
+ public object?[] _ctorArgs;
+ public string[] _namedParamNames;
+ public object?[] _namedParamValues;
+ private const int Field = 0x53;
+ private const int EnumType = 0x55;
+ private const int NullValue = 0xff;
+ private const int OneByteMask = 0x7f;
+ private const int TwoByteMask = 0x3f;
+ private const int FourByteMask = 0x1f;
+
+ internal static CustomAttributeInfo DecodeCustomAttribute(ConstructorInfo ctor, ReadOnlySpan<byte> binaryAttribute)
+ {
+ int pos = 2;
+ CustomAttributeInfo info = default;
+
+ if (binaryAttribute.Length < 2)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidCustomAttributeLength, ctor.DeclaringType, binaryAttribute.Length), nameof(binaryAttribute));
+ }
+ if ((binaryAttribute[0] != 0x01) || (binaryAttribute[1] != 0x00))
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidProlog, ctor.DeclaringType), nameof(binaryAttribute));
+ }
+
+ ParameterInfo[] pi = ctor.GetParameters();
+ info._ctor = ctor;
+ info._ctorArgs = new object?[pi.Length];
+ for (int i = 0; i < pi.Length; ++i)
+ {
+ info._ctorArgs[i] = DecodeCustomAttributeValue(pi[i].ParameterType, binaryAttribute, pos, out pos);
+ }
+ int numNamed = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(pos));
+ pos += 2;
+
+ info._namedParamNames = new string[numNamed];
+ info._namedParamValues = new object[numNamed];
+ for (int i = 0; i < numNamed; ++i)
+ {
+ int namedType = binaryAttribute[pos++];
+ int dataType = binaryAttribute[pos++];
+
+ if (dataType == EnumType)
+ {
+ // skip bytes for Enum type name;
+ int len2 = DecodeLen(binaryAttribute, pos, out pos);
+ pos += len2;
+ }
+
+ int len = DecodeLen(binaryAttribute, pos, out pos);
+ string name = StringFromBytes(binaryAttribute, pos, len);
+ info._namedParamNames[i] = name;
+ pos += len;
+
+ if (namedType == Field)
+ {
+ // For known pseudo custom attributes underlying Enum type is int
+ Type fieldType = dataType == EnumType ? typeof(int) : ElementTypeToType((PrimitiveSerializationTypeCode)dataType);
+ info._namedParamValues[i] = DecodeCustomAttributeValue(fieldType, binaryAttribute, pos, out pos); ;
+ }
+ else
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_UnknownNamedType, ctor.DeclaringType, namedType), nameof(binaryAttribute));
+ }
+ }
+
+ return info;
+ }
+
+ private static string StringFromBytes(ReadOnlySpan<byte> data, int pos, int len)
+ {
+ return Text.Encoding.UTF8.GetString(data.Slice(pos, len));
+ }
+
+ private static int DecodeLen(ReadOnlySpan<byte> data, int pos, out int rpos)
+ {
+ int len;
+ if ((data[pos] & 0x80) == 0)
+ {
+ len = (data[pos++] & OneByteMask);
+ }
+ else if ((data[pos] & 0x40) == 0)
+ {
+ len = ((data[pos] & TwoByteMask) << 8) + data[pos + 1];
+ pos += 2;
+ }
+ else
+ {
+ len = ((data[pos] & FourByteMask) << 24) + (data[pos + 1] << 16) + (data[pos + 2] << 8) + data[pos + 3];
+ pos += 4;
+ }
+ rpos = pos;
+ return len;
+ }
+
+ private static object? DecodeCustomAttributeValue(Type t, ReadOnlySpan<byte> data, int pos, out int rpos)
+ {
+ switch (Type.GetTypeCode(t))
+ {
+ case TypeCode.String:
+ if (data[pos] == NullValue)
+ {
+ rpos = pos + 1;
+ return null;
+ }
+ int len = DecodeLen(data, pos, out pos);
+ rpos = pos + len;
+ return StringFromBytes(data, pos, len);
+ case TypeCode.Int32:
+ rpos = pos + 4;
+ return BinaryPrimitives.ReadInt32LittleEndian(data.Slice(pos));
+ case TypeCode.Int16:
+ rpos = pos + 2;
+ return BinaryPrimitives.ReadInt16LittleEndian(data.Slice(pos));
+ case TypeCode.Boolean:
+ rpos = pos + 1;
+ return (data[pos] == 0) ? false : true;
+ case TypeCode.Object:
+ int subtype = data[pos];
+ pos += 1;
+
+ if (subtype >= 0x02 && subtype <= 0x0e)
+ {
+ return DecodeCustomAttributeValue(ElementTypeToType((PrimitiveSerializationTypeCode)subtype), data, pos, out rpos);
+ }
+ break;
+ }
+
+ throw new NotImplementedException(SR.Format(SR.NotImplemented_TypeForValue, t));
+ }
+
+ private static Type ElementTypeToType(PrimitiveSerializationTypeCode elementType) =>
+ elementType switch
+ {
+ PrimitiveSerializationTypeCode.Boolean => typeof(bool),
+ PrimitiveSerializationTypeCode.Char => typeof(char),
+ PrimitiveSerializationTypeCode.SByte => typeof(sbyte),
+ PrimitiveSerializationTypeCode.Byte => typeof(byte),
+ PrimitiveSerializationTypeCode.Int16 => typeof(short),
+ PrimitiveSerializationTypeCode.UInt16 => typeof(ushort),
+ PrimitiveSerializationTypeCode.Int32 => typeof(int),
+ PrimitiveSerializationTypeCode.UInt32 => typeof(uint),
+ PrimitiveSerializationTypeCode.Int64 => typeof(long),
+ PrimitiveSerializationTypeCode.UInt64 => typeof(ulong),
+ PrimitiveSerializationTypeCode.Single => typeof(float),
+ PrimitiveSerializationTypeCode.Double => typeof(double),
+ PrimitiveSerializationTypeCode.String => typeof(string),
+ _ => throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute"),
+ };
+ }
+}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Buffers.Binary;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
namespace System.Reflection.Emit
{
{
private readonly TypeBuilderImpl _typeBuilder;
private readonly string _fieldName;
- private readonly FieldAttributes _attributes;
private readonly Type _fieldType;
+ private FieldAttributes _attributes;
+
+ internal MarshallingInfo? _marshallingInfo;
+ internal int _offset;
+ internal List<CustomAttributeWrapper>? _customAttributes;
internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes)
{
_typeBuilder = typeBuilder;
_fieldType = type;
_attributes = attributes & ~FieldAttributes.ReservedMask;
+ _offset = -1;
}
- #region MemberInfo Overrides
protected override void SetConstantCore(object? defaultValue) => throw new NotImplementedException();
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException();
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ // Handle pseudo custom attributes
+ switch (con.ReflectedType!.FullName)
+ {
+ case "System.Runtime.InteropServices.FieldOffsetAttribute":
+ Debug.Assert(binaryAttribute.Length >= 6);
+ _offset = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(2));
+ return;
+ case "System.NonSerializedAttribute":
+#pragma warning disable SYSLIB0050 // 'FieldAttributes.NotSerialized' is obsolete: 'Formatter-based serialization is obsolete and should not be used'.
+ _attributes |= FieldAttributes.NotSerialized;
+#pragma warning restore SYSLIB0050
+ return;
+ case "System.Runtime.CompilerServices.SpecialNameAttribute":
+ _attributes |= FieldAttributes.SpecialName;
+ return;
+ case "System.Runtime.InteropServices.MarshalAsAttribute":
+ _attributes |= FieldAttributes.HasFieldMarshal;
+ _marshallingInfo = MarshallingInfo.ParseMarshallingInfo(con, binaryAttribute);
+ return;
+ }
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException();
- protected override void SetOffsetCore(int iOffset) => throw new NotImplementedException();
+ _customAttributes ??= new List<CustomAttributeWrapper>();
+ _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
+ }
+
+ protected override void SetOffsetCore(int iOffset)
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(iOffset);
+
+ _offset = iOffset;
+ }
+
+ #region MemberInfo Overrides
public override int MetadataToken => throw new NotImplementedException();
public override bool IsDefined(Type attributeType, bool inherit) => throw new NotSupportedException(SR.NotSupported_DynamicModule);
#endregion
+
+ internal sealed class MarshallingInfo
+ {
+ internal UnmanagedType _marshalType;
+ private int _marshalArrayElementType; // safe array: VarEnum; array: UnmanagedType
+ private int _marshalArrayElementCount; // number of elements in an array, length of a string, or Unspecified
+ private int _marshalParameterIndex; // index of parameter that specifies array size (short) or IID (int), or Unspecified
+ private object? _marshalTypeNameOrSymbol; // custom marshaller: string or Type; safe array: element type
+ private string? _marshalCookie;
+
+ internal const int Invalid = -1;
+ private const UnmanagedType InvalidUnmanagedType = (UnmanagedType)Invalid;
+ private const VarEnum InvalidVariantType = (VarEnum)Invalid;
+ internal const int MaxMarshalInteger = 0x1fffffff;
+
+ internal BlobHandle PopulateMarshallingBlob(MetadataBuilder builder)
+ {
+ var blobBuilder = new BlobBuilder();
+ SerializeMarshallingDescriptor(blobBuilder);
+ return builder.GetOrAddBlob(blobBuilder);
+
+ }
+
+ // The logic imported from https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs#L3543
+ internal void SerializeMarshallingDescriptor(BlobBuilder writer)
+ {
+ writer.WriteCompressedInteger((int)_marshalType);
+ switch (_marshalType)
+ {
+ case UnmanagedType.ByValArray: // NATIVE_TYPE_FIXEDARRAY
+ Debug.Assert(_marshalArrayElementCount >= 0);
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ if (_marshalArrayElementType >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalArrayElementType);
+ }
+ break;
+ case UnmanagedType.CustomMarshaler:
+ writer.WriteUInt16(0); // padding
+
+ switch (_marshalTypeNameOrSymbol)
+ {
+ case Type type:
+ writer.WriteSerializedString(type.FullName); // or AssemblyQualifiedName?
+ break;
+ case null:
+ writer.WriteByte(0);
+ break;
+ default:
+ writer.WriteSerializedString((string)_marshalTypeNameOrSymbol);
+ break;
+ }
+
+ if (_marshalCookie != null)
+ {
+ writer.WriteSerializedString(_marshalCookie);
+ }
+ else
+ {
+ writer.WriteByte(0);
+ }
+ break;
+ case UnmanagedType.LPArray: // NATIVE_TYPE_ARRAY
+ Debug.Assert(_marshalArrayElementType >= 0);
+ writer.WriteCompressedInteger(_marshalArrayElementType);
+ if (_marshalParameterIndex >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalParameterIndex);
+ if (_marshalArrayElementCount >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ writer.WriteByte(1); // The parameter number is valid
+ }
+ }
+ else if (_marshalArrayElementCount >= 0)
+ {
+ writer.WriteByte(0); // Dummy parameter value emitted so that NumberOfElements can be in a known position
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ writer.WriteByte(0); // The parameter number is not valid
+ }
+ break;
+ case UnmanagedType.SafeArray:
+ VarEnum safeArrayElementSubtype = (VarEnum)_marshalArrayElementType;
+ if (safeArrayElementSubtype >= 0)
+ {
+ writer.WriteCompressedInteger((int)safeArrayElementSubtype);
+
+ if (_marshalTypeNameOrSymbol is Type elementType)
+ {
+ writer.WriteSerializedString(elementType.FullName);
+ }
+ }
+ break;
+ case UnmanagedType.ByValTStr: // NATIVE_TYPE_FIXEDSYSSTRING
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ break;
+
+ case UnmanagedType.Interface:
+ case UnmanagedType.IDispatch:
+ case UnmanagedType.IUnknown:
+ if (_marshalParameterIndex >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalParameterIndex);
+ }
+ break;
+ }
+ }
+
+ internal void SetMarshalAsCustom(object typeSymbolOrName, string? cookie)
+ {
+ _marshalType = UnmanagedType.CustomMarshaler;
+ _marshalTypeNameOrSymbol = typeSymbolOrName;
+ _marshalCookie = cookie;
+ }
+
+ internal void SetMarshalAsComInterface(UnmanagedType unmanagedType, int? parameterIndex)
+ {
+ Debug.Assert(parameterIndex == null || parameterIndex >= 0 && parameterIndex <= MaxMarshalInteger);
+
+ _marshalType = unmanagedType;
+ _marshalParameterIndex = parameterIndex ?? Invalid;
+ }
+
+ internal void SetMarshalAsArray(UnmanagedType? elementType, int? elementCount, short? parameterIndex)
+ {
+ Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger);
+ Debug.Assert(parameterIndex == null || parameterIndex >= 0);
+
+ _marshalType = UnmanagedType.LPArray;
+ _marshalArrayElementType = (int)(elementType ?? (UnmanagedType)0x50);
+ _marshalArrayElementCount = elementCount ?? Invalid;
+ _marshalParameterIndex = parameterIndex ?? Invalid;
+ }
+
+ internal void SetMarshalAsFixedArray(UnmanagedType? elementType, int? elementCount)
+ {
+ Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger);
+ Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger);
+
+ _marshalType = UnmanagedType.ByValArray;
+ _marshalArrayElementType = (int)(elementType ?? InvalidUnmanagedType);
+ _marshalArrayElementCount = elementCount ?? Invalid;
+ }
+
+ internal void SetMarshalAsSafeArray(VarEnum? elementType, Type? type)
+ {
+ Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger);
+
+ _marshalType = UnmanagedType.SafeArray;
+ _marshalArrayElementType = (int)(elementType ?? InvalidVariantType);
+ _marshalTypeNameOrSymbol = type;
+ }
+
+ internal void SetMarshalAsFixedString(int elementCount)
+ {
+ Debug.Assert(elementCount >= 0 && elementCount <= MaxMarshalInteger);
+
+ _marshalType = UnmanagedType.ByValTStr;
+ _marshalArrayElementCount = elementCount;
+ }
+
+ internal void SetMarshalAsSimpleType(UnmanagedType type)
+ {
+ Debug.Assert(type >= 0 && (int)type <= MaxMarshalInteger);
+ _marshalType = type;
+ }
+
+ // The logic imported from https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Symbols/Attributes/MarshalAsAttributeDecoder.cs
+ internal static MarshallingInfo ParseMarshallingInfo(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ CustomAttributeInfo attributeInfo = CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute);
+ MarshallingInfo info = new();
+ UnmanagedType unmanagedType;
+
+ if (attributeInfo._ctorArgs[0] is short shortValue)
+ {
+ unmanagedType = (UnmanagedType)shortValue;
+ }
+ else
+ {
+ unmanagedType = (UnmanagedType)attributeInfo._ctorArgs[0]!;
+ }
+
+ switch (unmanagedType)
+ {
+ case UnmanagedType.CustomMarshaler:
+ DecodeMarshalAsCustom(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
+ break;
+ case UnmanagedType.Interface:
+ case UnmanagedType.IDispatch:
+ case UnmanagedType.IUnknown:
+ DecodeMarshalAsComInterface(attributeInfo._namedParamNames, attributeInfo._namedParamValues, unmanagedType, info);
+ break;
+ case UnmanagedType.LPArray:
+ DecodeMarshalAsArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, isFixed: false, info);
+ break;
+ case UnmanagedType.ByValArray:
+ DecodeMarshalAsArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, isFixed: true, info);
+ break;
+ case UnmanagedType.SafeArray:
+ DecodeMarshalAsSafeArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
+ break;
+ case UnmanagedType.ByValTStr:
+ DecodeMarshalAsFixedString(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
+ break;
+#pragma warning disable CS0618 // Type or member is obsolete
+ case UnmanagedType.VBByRefStr:
+#pragma warning restore CS0618
+ // named parameters ignored with no error
+ info.SetMarshalAsSimpleType(unmanagedType);
+ break;
+ default:
+ if ((int)unmanagedType < 0 || (int)unmanagedType > MaxMarshalInteger)
+ {
+ throw new ArgumentException(SR.Argument_InvalidTypeArgument, nameof(binaryAttribute));
+ }
+ else
+ {
+ // named parameters ignored with no error
+ info.SetMarshalAsSimpleType(unmanagedType);
+ }
+ break;
+ }
+
+ return info;
+ }
+
+ private static void DecodeMarshalAsFixedString(string[] paramNames, object?[] values, MarshallingInfo info)
+ {
+ int elementCount = -1;
+
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "SizeConst":
+ elementCount = (int)values[i]!;
+ break;
+ case "ArraySubType":
+ case "SizeParamIndex":
+ throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
+ // other parameters ignored with no error
+ }
+ }
+
+ if (elementCount < 0)
+ {
+ // SizeConst must be specified:
+ throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
+ }
+
+ info.SetMarshalAsFixedString(elementCount);
+ }
+
+ private static void DecodeMarshalAsSafeArray(string[] paramNames, object?[] values, MarshallingInfo info)
+ {
+ VarEnum? elementTypeVariant = null;
+ Type? elementType = null;
+ int symbolIndex = -1;
+
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "SafeArraySubType":
+ elementTypeVariant = (VarEnum)values[i]!;
+ break;
+ case "SafeArrayUserDefinedSubType":
+ elementType = (Type?)values[i];
+ symbolIndex = i;
+ break;
+ case "ArraySubType":
+ case "SizeConst":
+ case "SizeParamIndex":
+ throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
+ // other parameters ignored with no error
+ }
+ }
+
+ switch (elementTypeVariant)
+ {
+ case VarEnum.VT_DISPATCH:
+ case VarEnum.VT_UNKNOWN:
+ case VarEnum.VT_RECORD:
+ // only these variants accept specification of user defined subtype
+ break;
+
+ default:
+ if (elementTypeVariant != null && symbolIndex >= 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
+ }
+ else
+ {
+ // type ignored:
+ elementType = null;
+ }
+ break;
+ }
+
+ info.SetMarshalAsSafeArray(elementTypeVariant, elementType);
+ }
+
+ private static void DecodeMarshalAsArray(string[] paramNames, object?[] values, bool isFixed, MarshallingInfo info)
+ {
+ UnmanagedType? elementType = null;
+ int? elementCount = isFixed ? 1 : null;
+ short? parameterIndex = null;
+
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "ArraySubType":
+ elementType = (UnmanagedType)values[i]!;
+ break;
+ case "SizeConst":
+ elementCount = (int?)values[i];
+ break;
+ case "SizeParamIndex":
+ if (isFixed)
+ {
+ goto case "SafeArraySubType";
+ }
+ parameterIndex = (short?)values[i];
+ break;
+ case "SafeArraySubType":
+ throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
+ // other parameters ignored with no error
+ }
+ }
+
+ if (isFixed)
+ {
+ info.SetMarshalAsFixedArray(elementType, elementCount);
+ }
+ else
+ {
+ info.SetMarshalAsArray(elementType, elementCount, parameterIndex);
+ }
+ }
+
+ private static void DecodeMarshalAsComInterface(string[] paramNames, object?[] values, UnmanagedType unmanagedType, MarshallingInfo info)
+ {
+ int? parameterIndex = null;
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ if (paramNames[i] == "IidParameterIndex")
+ {
+ parameterIndex = (int?)values[i];
+ break;
+ }
+ }
+ info.SetMarshalAsComInterface(unmanagedType, parameterIndex);
+ }
+
+ private static void DecodeMarshalAsCustom(string[] paramNames, object?[] values, MarshallingInfo info)
+ {
+ string? cookie = null;
+ Type? type = null;
+ string? name = null;
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "MarshalType":
+ name = (string?)values[i];
+ break;
+ case "MarshalTypeRef":
+ type = (Type?)values[i];
+ break;
+ case "MarshalCookie":
+ cookie = (string?)values[i];
+ break;
+ // other parameters ignored with no error
+ }
+ }
+
+ info.SetMarshalAsCustom((object?)name ?? type!, cookie);
+ }
+ }
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Buffers.Binary;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection.Metadata;
+using System.Runtime.InteropServices;
namespace System.Reflection.Emit
{
private readonly Type _returnType;
private readonly Type[]? _parameterTypes;
private readonly ModuleBuilderImpl _module;
- private readonly MethodAttributes _attributes;
private readonly string _name;
private readonly CallingConventions _callingConventions;
private readonly TypeBuilderImpl _declaringType;
+ private MethodAttributes _attributes;
+ private MethodImplAttributes _methodImplFlags;
+
+ internal DllImportData? _dllImportData;
+ internal List<CustomAttributeWrapper>? _customAttributes;
internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConventions, Type? returnType,
Type[]? parameterTypes, ModuleBuilderImpl module, TypeBuilderImpl declaringType)
ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
}
}
+
+ _methodImplFlags = MethodImplAttributes.IL;
}
internal BlobBuilder GetMethodSignatureBlob() =>
protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names) => throw new NotImplementedException();
protected override ParameterBuilder DefineParameterCore(int position, ParameterAttributes attributes, string? strParamName) => throw new NotImplementedException();
protected override ILGenerator GetILGeneratorCore(int size) => throw new NotImplementedException();
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException();
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException();
- protected override void SetImplementationFlagsCore(MethodImplAttributes attributes) => throw new NotImplementedException();
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ // Handle pseudo custom attributes
+ switch (con.ReflectedType!.FullName)
+ {
+ case "System.Runtime.CompilerServices.MethodImplAttribute":
+ int implValue = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2));
+ _methodImplFlags |= (MethodImplAttributes)implValue;
+ return;
+ case "System.Runtime.InteropServices.DllImportAttribute":
+ {
+ _dllImportData = DllImportData.CreateDllImportData(CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute), out var preserveSig);
+ _attributes |= MethodAttributes.PinvokeImpl;
+ if (preserveSig)
+ {
+ _methodImplFlags |= MethodImplAttributes.PreserveSig;
+ }
+ }
+ return;
+ case "System.Runtime.InteropServices.PreserveSigAttribute":
+ _methodImplFlags |= MethodImplAttributes.PreserveSig;
+ return;
+ case "System.Runtime.CompilerServices.SpecialNameAttribute":
+ _attributes |= MethodAttributes.SpecialName;
+ return;
+ case "System.Security.SuppressUnmanagedCodeSecurityAttribute":
+ _attributes |= MethodAttributes.HasSecurity;
+ break;
+ }
+
+ _customAttributes ??= new List<CustomAttributeWrapper>();
+ _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
+ }
+
+ protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
+ {
+ _methodImplFlags = attributes;
+ }
protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes,
Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers) => throw new NotImplementedException();
public override string Name => _name;
=> throw new NotImplementedException();
public override MethodImplAttributes GetMethodImplementationFlags()
- => throw new NotImplementedException();
+ => _methodImplFlags;
public override ParameterInfo[] GetParameters()
=> throw new NotImplementedException();
public override MethodInfo MakeGenericMethod(params System.Type[] typeArguments)
=> throw new NotImplementedException();
}
+
+ internal sealed class DllImportData
+ {
+ private readonly string _moduleName;
+ private readonly string? _entryPoint;
+ private readonly MethodImportAttributes _flags;
+ internal DllImportData(string moduleName, string? entryPoint, MethodImportAttributes flags)
+ {
+ _moduleName = moduleName;
+ _entryPoint = entryPoint;
+ _flags = flags;
+ }
+
+ public string ModuleName => _moduleName;
+
+ public string? EntryPoint => _entryPoint;
+
+ public MethodImportAttributes Flags => _flags;
+
+ internal static DllImportData CreateDllImportData(CustomAttributeInfo attr, out bool preserveSig)
+ {
+ string? moduleName = (string?)attr._ctorArgs[0];
+ if (moduleName == null || moduleName.Length == 0)
+ {
+ throw new ArgumentException(SR.Argument_DllNameCannotBeEmpty);
+ }
+
+ MethodImportAttributes importAttributes = MethodImportAttributes.None;
+ string? entryPoint = null;
+ preserveSig = true;
+ for (int i = 0; i < attr._namedParamNames.Length; ++i)
+ {
+ string name = attr._namedParamNames[i];
+ object value = attr._namedParamValues[i]!;
+ switch (name)
+ {
+ case "PreserveSig":
+ preserveSig = (bool)value;
+ break;
+ case "CallingConvention":
+ importAttributes |= (CallingConvention)value switch
+ {
+ CallingConvention.Cdecl => MethodImportAttributes.CallingConventionCDecl,
+ CallingConvention.FastCall => MethodImportAttributes.CallingConventionFastCall,
+ CallingConvention.StdCall => MethodImportAttributes.CallingConventionStdCall,
+ CallingConvention.ThisCall => MethodImportAttributes.CallingConventionThisCall,
+ _=> MethodImportAttributes.CallingConventionWinApi // Roslyn defaults with this
+ };
+ break;
+ case "CharSet":
+ importAttributes |= (CharSet)value switch
+ {
+ CharSet.Ansi => MethodImportAttributes.CharSetAnsi,
+ CharSet.Auto => MethodImportAttributes.CharSetAuto,
+ CharSet.Unicode => MethodImportAttributes.CharSetUnicode,
+ _ => MethodImportAttributes.CharSetAuto
+ };
+ break;
+ case "EntryPoint":
+ entryPoint = (string?)value;
+ break;
+ case "ExactSpelling":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.ExactSpelling;
+ }
+ break;
+ case "SetLastError":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.SetLastError;
+ }
+ break;
+ case "BestFitMapping":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.BestFitMappingEnable;
+ }
+ else
+ {
+ importAttributes |= MethodImportAttributes.BestFitMappingDisable;
+ }
+ break;
+ case "ThrowOnUnmappableChar":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.ThrowOnUnmappableCharEnable;
+ }
+ else
+ {
+ importAttributes |= MethodImportAttributes.ThrowOnUnmappableCharDisable;
+ }
+ break;
+ }
+ }
+
+ return new DllImportData(moduleName, entryPoint, importAttributes);
+ }
+ }
}
private readonly Dictionary<Assembly, AssemblyReferenceHandle> _assemblyReferences = new();
private readonly Dictionary<Type, TypeReferenceHandle> _typeReferences = new();
private readonly List<TypeBuilderImpl> _typeDefinitions = new();
+ private readonly Dictionary<ConstructorInfo, MemberReferenceHandle> _ctorReferences = new();
+ private Dictionary<string, ModuleReferenceHandle>? _moduleReferences;
+ private List<CustomAttributeWrapper>? _customAttributes;
private int _nextTypeDefRowId = 1;
private int _nextMethodDefRowId = 1;
private int _nextFieldDefRowId = 1;
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Types are preserved via s_coreTypes")]
- internal Type GetTypeFromCoreAssembly(CoreTypeId typeId)
+ internal Type GetTypeFromCoreAssembly(CoreTypeId typeId)
{
if (_coreTypes == null)
{
internal void AppendMetadata()
{
// Add module metadata
- _metadataBuilder.AddModule(
+ ModuleDefinitionHandle moduleHandle = _metadataBuilder.AddModule(
generation: 0,
moduleName: _metadataBuilder.GetOrAddString(_name),
mvid: _metadataBuilder.GetOrAddGuid(Guid.NewGuid()),
name: _metadataBuilder.GetOrAddString("<Module>"),
baseType: default,
fieldList: MetadataTokens.FieldDefinitionHandle(1),
- methodList: MetadataTokens.MethodDefinitionHandle(1)); ;
+ methodList: MetadataTokens.MethodDefinitionHandle(1));
+
+ WriteCustomAttributes(_customAttributes, moduleHandle);
// Add each type definition to metadata table.
foreach (TypeBuilderImpl typeBuilder in _typeDefinitions)
TypeDefinitionHandle typeDefinitionHandle = AddTypeDefinition(typeBuilder, parent, _nextMethodDefRowId, _nextFieldDefRowId);
Debug.Assert(typeBuilder._handle.Equals(typeDefinitionHandle));
+ WriteCustomAttributes(typeBuilder._customAttributes, typeDefinitionHandle);
- // Add each method definition to metadata table.
- foreach (MethodBuilderImpl method in typeBuilder._methodDefStore)
+ foreach (MethodBuilderImpl method in typeBuilder._methodDefinitions)
{
- AddMethodDefinition(method, method.GetMethodSignatureBlob());
+ MethodDefinitionHandle methodHandle = AddMethodDefinition(method, method.GetMethodSignatureBlob());
+ WriteCustomAttributes(method._customAttributes, methodHandle);
_nextMethodDefRowId++;
+
+ if (method._dllImportData != null)
+ {
+ AddMethodImport(methodHandle, method._dllImportData.EntryPoint ?? method.Name,
+ method._dllImportData.Flags, GetModuleReference(method._dllImportData.ModuleName));
+ }
}
- foreach (FieldBuilderImpl field in typeBuilder._fieldDefStore)
+ foreach (FieldBuilderImpl field in typeBuilder._fieldDefinitions)
{
- AddFieldDefinition(field, MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType, this));
+ FieldDefinitionHandle fieldHandle = AddFieldDefinition(field, MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType, this));
+ WriteCustomAttributes(field._customAttributes, fieldHandle);
_nextFieldDefRowId++;
+
+ if (field._offset > 0 && (typeBuilder.Attributes & TypeAttributes.ExplicitLayout) != 0)
+ {
+ AddFieldLayout(fieldHandle, field._offset);
+ }
+
+ if (field._marshallingInfo != null)
+ {
+ AddFieldMarshalling(fieldHandle, field._marshallingInfo.PopulateMarshallingBlob(_metadataBuilder));
+ }
}
}
}
+ private ModuleReferenceHandle GetModuleReference(string moduleName)
+ {
+ _moduleReferences ??= new Dictionary<string, ModuleReferenceHandle>();
+
+ if (!_moduleReferences.TryGetValue(moduleName, out var handle))
+ {
+ handle = AddModuleReference(moduleName);
+ _moduleReferences.Add(moduleName, handle);
+ }
+
+ return handle;
+ }
+
+ internal void WriteCustomAttributes(List<CustomAttributeWrapper>? customAttributes, EntityHandle parent)
+ {
+ if (customAttributes != null)
+ {
+ foreach (CustomAttributeWrapper customAttribute in customAttributes)
+ {
+ _metadataBuilder.AddCustomAttribute(parent, GetConstructorHandle(customAttribute.Ctor),
+ _metadataBuilder.GetOrAddBlob(customAttribute.Data));
+ }
+ }
+ }
+
+ private MemberReferenceHandle GetConstructorHandle(ConstructorInfo constructorInfo)
+ {
+ if (!_ctorReferences.TryGetValue(constructorInfo, out var constructorHandle))
+ {
+ TypeReferenceHandle parentHandle = GetTypeReference(constructorInfo.DeclaringType!);
+ constructorHandle = AddConstructorReference(parentHandle, constructorInfo);
+ _ctorReferences.Add(constructorInfo, constructorHandle);
+ }
+
+ return constructorHandle;
+ }
+
+ private TypeReferenceHandle GetTypeReference(Type type)
+ {
+ if (!_typeReferences.TryGetValue(type, out var typeHandle))
+ {
+ typeHandle = AddTypeReference(type, GetAssemblyReference(type.Assembly));
+ _typeReferences.Add(type, typeHandle);
+ }
+
+ return typeHandle;
+ }
+
+ private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly)
+ {
+ if (!_assemblyReferences.TryGetValue(assembly, out var handle))
+ {
+ AssemblyName aName = assembly.GetName();
+ handle = AddAssemblyReference(aName.Name!, aName.Version, aName.CultureName, aName.GetPublicKeyToken(), aName.Flags, aName.ContentType);
+ _assemblyReferences.Add(assembly, handle);
+ }
+
+ return handle;
+ }
+
private FieldDefinitionHandle AddFieldDefinition(FieldBuilderImpl field, BlobBuilder fieldSignature) =>
_metadataBuilder.AddFieldDefinition(
attributes: field.Attributes,
private MethodDefinitionHandle AddMethodDefinition(MethodBuilderImpl method, BlobBuilder methodSignature) =>
_metadataBuilder.AddMethodDefinition(
attributes: method.Attributes,
- implAttributes: MethodImplAttributes.IL,
+ implAttributes: method.GetMethodImplementationFlags(),
name: _metadataBuilder.GetOrAddString(method.Name),
signature: _metadataBuilder.GetOrAddBlob(methodSignature),
bodyOffset: -1, // No body supported yet
- parameterList: MetadataTokens.ParameterHandle(1)
- );
+ parameterList: MetadataTokens.ParameterHandle(1));
private TypeReferenceHandle AddTypeReference(Type type, AssemblyReferenceHandle parent) =>
_metadataBuilder.AddTypeReference(
resolutionScope: parent,
@namespace: (type.Namespace == null) ? default : _metadataBuilder.GetOrAddString(type.Namespace),
- name: _metadataBuilder.GetOrAddString(type.Name)
- );
+ name: _metadataBuilder.GetOrAddString(type.Name));
- private TypeReferenceHandle GetTypeReference(Type type)
+ private MemberReferenceHandle AddConstructorReference(TypeReferenceHandle parent, ConstructorInfo method)
{
- if (!_typeReferences.TryGetValue(type, out var parentHandle))
- {
- parentHandle = AddTypeReference(type, GetAssemblyReference(type.Assembly));
- _typeReferences.Add(type, parentHandle);
- }
-
- return parentHandle;
+ var blob = MetadataSignatureHelper.ConstructorSignatureEncoder(method.GetParameters(), this);
+ return _metadataBuilder.AddMemberReference(
+ parent: parent,
+ name: _metadataBuilder.GetOrAddString(method.Name),
+ signature: _metadataBuilder.GetOrAddBlob(blob));
}
- private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly)
- {
- if (!_assemblyReferences.TryGetValue(assembly, out var handle))
- {
- AssemblyName aName = assembly.GetName();
- handle = AddAssemblyReference(aName.Name!, aName.Version, aName.CultureName, aName.GetPublicKeyToken(), aName.Flags, aName.ContentType);
- _assemblyReferences.Add(assembly, handle);
- }
+ private void AddMethodImport(MethodDefinitionHandle methodHandle, string name,
+ MethodImportAttributes attributes, ModuleReferenceHandle moduleHandle) =>
+ _metadataBuilder.AddMethodImport(
+ method: methodHandle,
+ attributes: attributes,
+ name: _metadataBuilder.GetOrAddString(name),
+ module: moduleHandle);
- return handle;
+ private ModuleReferenceHandle AddModuleReference(string moduleName) =>
+ _metadataBuilder.AddModuleReference(moduleName: _metadataBuilder.GetOrAddString(moduleName));
+
+ private void AddFieldLayout(FieldDefinitionHandle fieldHandle, int offset) =>
+ _metadataBuilder.AddFieldLayout(field: fieldHandle, offset: offset);
+
+ private void AddFieldMarshalling(FieldDefinitionHandle fieldHandle, BlobHandle descriptor)
+ {
+ _metadataBuilder.AddMarshallingDescriptor(fieldHandle, descriptor);
}
- private AssemblyReferenceHandle AddAssemblyReference(string name, Version? version,
- string? culture, byte[]? publicKeyToken, AssemblyNameFlags flags, AssemblyContentType contentType) =>
+ private AssemblyReferenceHandle AddAssemblyReference(string name, Version? version, string? culture,
+ byte[]? publicKeyToken, AssemblyNameFlags flags, AssemblyContentType contentType) =>
_metadataBuilder.AddAssemblyReference(
name: _metadataBuilder.GetOrAddString(name),
version: version ?? new Version(0, 0, 0, 0),
protected override TypeBuilder DefineTypeCore(string name, TypeAttributes attr, [DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] Type? parent, Type[]? interfaces, PackingSize packingSize, int typesize)
{
TypeDefinitionHandle typeHandle = MetadataTokens.TypeDefinitionHandle(++_nextTypeDefRowId);
- TypeBuilderImpl _type = new TypeBuilderImpl(name, attr, parent, this, typeHandle);
+ TypeBuilderImpl _type = new TypeBuilderImpl(name, attr, parent, this, typeHandle, packingSize, typesize);
_typeDefinitions.Add(_type);
return _type;
}
protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes) => throw new NotImplementedException();
protected override MethodInfo GetArrayMethodCore(Type arrayClass, string methodName, CallingConventions callingConvention, Type? returnType, Type[]? parameterTypes) => throw new NotImplementedException();
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotSupportedException();
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotSupportedException();
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ _customAttributes ??= new List<CustomAttributeWrapper>();
+ _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
+ }
public override int GetSignatureMetadataToken(SignatureHelper signature) => throw new NotImplementedException();
}
}
// 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;
using System.Reflection.Metadata.Ecma335;
return fieldSignature;
}
+ internal static BlobBuilder ConstructorSignatureEncoder(ParameterInfo[]? parameters, ModuleBuilderImpl module)
+ {
+ BlobBuilder constructorSignature = new();
+
+ new BlobEncoder(constructorSignature).
+ MethodSignature(isInstanceMethod: true).
+ Parameters((parameters == null) ? 0 : parameters.Length, out ReturnTypeEncoder retType, out ParametersEncoder parameterEncoder);
+
+ retType.Void();
+
+ if (parameters != null)
+ {
+ Type[]? typeParameters = Array.ConvertAll(parameters, parameter => parameter.ParameterType);
+
+ foreach (Type parameter in typeParameters)
+ {
+ WriteSignatureForType(parameterEncoder.AddParameter().Type(), parameter, module);
+ }
+ }
+
+ return constructorSignature;
+ }
+
internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters, Type? returnType, bool isInstance)
{
// Encoding return type and parameters.
BlobBuilder methodSignature = new();
- ParametersEncoder parEncoder;
- ReturnTypeEncoder retEncoder;
-
new BlobEncoder(methodSignature).
MethodSignature(isInstanceMethod: isInstance).
- Parameters((parameters == null) ? 0 : parameters.Length, out retEncoder, out parEncoder);
+ Parameters((parameters == null) ? 0 : parameters.Length, out ReturnTypeEncoder retEncoder, out ParametersEncoder parEncoder);
if (returnType != null && returnType != module.GetTypeFromCoreAssembly(CoreTypeId.Void))
{
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.InteropServices;
using System.Globalization;
+using System.Runtime.InteropServices;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
{
internal sealed class TypeBuilderImpl : TypeBuilder
{
- internal List<MethodBuilderImpl> _methodDefStore = new();
- internal List<FieldBuilderImpl> _fieldDefStore = new();
private readonly ModuleBuilderImpl _module;
private readonly string _name;
private readonly string? _namespace;
- internal readonly TypeDefinitionHandle _handle;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private Type? _typeParent;
private TypeAttributes _attributes;
+ private PackingSize _packingSize;
+ private int _typeSize;
+
+ internal readonly TypeDefinitionHandle _handle;
+ internal readonly List<MethodBuilderImpl> _methodDefinitions = new();
+ internal readonly List<FieldBuilderImpl> _fieldDefinitions = new();
+ internal List<CustomAttributeWrapper>? _customAttributes;
internal TypeBuilderImpl(string fullName, TypeAttributes typeAttributes,
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, ModuleBuilderImpl module, TypeDefinitionHandle handle)
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, ModuleBuilderImpl module,
+ TypeDefinitionHandle handle, PackingSize packingSize, int typeSize)
{
_name = fullName;
_module = module;
_attributes = typeAttributes;
+ _packingSize = packingSize;
+ _typeSize = typeSize;
SetParent(parent);
_handle = handle;
}
internal ModuleBuilderImpl GetModuleBuilder() => _module;
- protected override PackingSize PackingSizeCore => throw new NotImplementedException();
- protected override int SizeCore => throw new NotImplementedException();
+ protected override PackingSize PackingSizeCore => _packingSize;
+ protected override int SizeCore => _typeSize;
protected override void AddInterfaceImplementationCore([DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] Type interfaceType) => throw new NotImplementedException();
[return: DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))]
protected override TypeInfo CreateTypeInfoCore() => throw new NotImplementedException();
protected override FieldBuilder DefineFieldCore(string fieldName, Type type, Type[]? requiredCustomModifiers, Type[]? optionalCustomModifiers, FieldAttributes attributes)
{
var field = new FieldBuilderImpl(this, fieldName, type, attributes);
- _fieldDefStore.Add(field);
+ _fieldDefinitions.Add(field);
return field;
}
protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names) => throw new NotImplementedException();
protected override MethodBuilder DefineMethodCore(string name, MethodAttributes attributes, CallingConventions callingConvention, Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers)
{
MethodBuilderImpl methodBuilder = new(name, attributes, callingConvention, returnType, parameterTypes, _module, this);
- _methodDefStore.Add(methodBuilder);
+ _methodDefinitions.Add(methodBuilder);
return methodBuilder;
}
protected override ConstructorBuilder DefineTypeInitializerCore() => throw new NotImplementedException();
protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes) => throw new NotImplementedException();
protected override bool IsCreatedCore() => throw new NotImplementedException();
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException();
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException();
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ // Handle pseudo custom attributes
+ switch (con.ReflectedType!.FullName)
+ {
+ case "System.Runtime.InteropServices.StructLayoutAttribute":
+ ParseStructLayoutAttribute(con, binaryAttribute);
+ return;
+ case "System.Runtime.CompilerServices.SpecialNameAttribute":
+ _attributes |= TypeAttributes.SpecialName;
+ return;
+ case "System.SerializableAttribute":
+#pragma warning disable SYSLIB0050 // 'TypeAttributes.Serializable' is obsolete: 'Formatter-based serialization is obsolete and should not be used'.
+ _attributes |= TypeAttributes.Serializable;
+#pragma warning restore SYSLIB0050
+ return;
+ case "System.Runtime.InteropServices.ComImportAttribute":
+ _attributes |= TypeAttributes.Import;
+ return;
+ case "System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeImportAttribute":
+ _attributes |= TypeAttributes.WindowsRuntime;
+ return;
+ case "System.Security.SuppressUnmanagedCodeSecurityAttribute": // It says has no effect in .NET Core, maybe remove?
+ _attributes |= TypeAttributes.HasSecurity;
+ break;
+ }
+
+ _customAttributes ??= new List<CustomAttributeWrapper>();
+ _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
+ }
+
+ private void ParseStructLayoutAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ CustomAttributeInfo attributeInfo = CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute);
+ LayoutKind layoutKind = (LayoutKind)attributeInfo._ctorArgs[0]!;
+ _attributes &= ~TypeAttributes.LayoutMask;
+ _attributes |= layoutKind switch
+ {
+ LayoutKind.Auto => TypeAttributes.AutoLayout,
+ LayoutKind.Explicit => TypeAttributes.ExplicitLayout,
+ LayoutKind.Sequential => TypeAttributes.SequentialLayout,
+ _ => TypeAttributes.AutoLayout,
+ };
+
+ for (int i = 0; i < attributeInfo._namedParamNames.Length; ++i)
+ {
+ string name = attributeInfo._namedParamNames[i];
+ int value = (int)attributeInfo._namedParamValues[i]!;
+
+ switch (name)
+ {
+ case "CharSet":
+ switch ((CharSet)value)
+ {
+ case CharSet.None:
+ case CharSet.Ansi:
+ _attributes &= ~(TypeAttributes.UnicodeClass | TypeAttributes.AutoClass);
+ break;
+ case CharSet.Unicode:
+ _attributes &= ~TypeAttributes.AutoClass;
+ _attributes |= TypeAttributes.UnicodeClass;
+ break;
+ case CharSet.Auto:
+ _attributes &= ~TypeAttributes.UnicodeClass;
+ _attributes |= TypeAttributes.AutoClass;
+ break;
+ }
+ break;
+ case "Pack":
+ _packingSize = (PackingSize)value;
+ break;
+ case "Size":
+ _typeSize = value;
+ break;
+ default:
+ throw new ArgumentException(SR.Format(SR.Argument_UnknownNamedType, con.DeclaringType, name), nameof(binaryAttribute));
+ }
+ }
+ }
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2074:DynamicallyAccessedMembers",
Justification = "TODO: Need to figure out how to preserve System.Object public constructor")]
}
[Fact]
- public void SetCustomAttribute_ConstructorInfo_ByteArray_NullBinaryAttribute_ThrowsArgumentNullException()
- {
- TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
- string[] typeParamNames = new string[] { "TFirst" };
- GenericTypeParameterBuilder[] typeParams = type.DefineGenericParameters(typeParamNames);
- ConstructorInfo attributeConstructor = typeof(HelperAttribute).GetConstructor(new Type[0]);
-
- AssertExtensions.Throws<ArgumentNullException>("binaryAttribute", () => typeParams[0].SetCustomAttribute(attributeConstructor, null));
- }
-
- [Fact]
public void SetCustomAttribute_CustomAttributeBuilder()
{
TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+using Xunit;
+
+namespace System.Reflection.Emit.Tests
+{
+ [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ public class AssemblySaveCustomAttributeTests
+ {
+ private List<CustomAttributeBuilder> _attributes = new List<CustomAttributeBuilder>
+ {
+ new CustomAttributeBuilder(s_comVisiblePair.con, s_comVisiblePair.args),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args)
+ };
+
+ private static readonly Type s_comVisibleType = typeof(ComVisibleAttribute);
+ private static readonly Type s_guideType = typeof(GuidAttribute);
+ private static readonly (ConstructorInfo con, object[] args) s_comVisiblePair = (s_comVisibleType.GetConstructor(new Type[] { typeof(bool) }), new object[] { true });
+ private static readonly (ConstructorInfo con, object[] args) s_guidPair = (s_guideType.GetConstructor(new Type[] { typeof(string) }), new object[] { "9ED54F84-A89D-4fcd-A854-44251E925F09" });
+
+ private static AssemblyName PopulateAssemblyName()
+ {
+ AssemblyName assemblyName = new AssemblyName("MyDynamicAssembly");
+ assemblyName.Version = new Version("7.0.0.0");
+ assemblyName.CultureInfo = Globalization.CultureInfo.InvariantCulture;
+ return assemblyName;
+ }
+
+ [Fact]
+ public void AssemblyModuleWithCustomAttributes()
+ {
+ AssemblyName assemblyName = PopulateAssemblyName();
+
+ using (TempFile file = TempFile.Create())
+ {
+ WriteAssemblyToDisk(assemblyName, Type.EmptyTypes, file.Path, _attributes, _attributes);
+
+ Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
+ Module moduleFromDisk = assemblyFromDisk.Modules.First();
+
+ AssemblyTools.AssertAssemblyNameAndModule(assemblyName, assemblyFromDisk.GetName(), moduleFromDisk);
+ ValidateAttributes(assemblyFromDisk.GetCustomAttributesData());
+ ValidateAttributes(moduleFromDisk.GetCustomAttributesData());
+ }
+ }
+
+ [Fact]
+ public void MethodFieldWithCustomAttributes()
+ {
+ Type[] types = new Type[] { typeof(IMultipleMethod), typeof(IOneMethod), typeof(StructWithFields) };
+
+ using (TempFile file = TempFile.Create())
+ {
+ WriteAssemblyToDisk(PopulateAssemblyName(), types, file.Path, typeAttributes: _attributes,
+ methodAttributes: _attributes, fieldAttributes: _attributes);
+
+ Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
+
+ Module moduleFromDisk = assemblyFromDisk.Modules.First();
+ Type[] typesFromDisk = moduleFromDisk.GetTypes();
+
+ Assert.Equal(types.Length, typesFromDisk.Length);
+
+ for (int i = 0; i < types.Length; i++)
+ {
+ Type typeFromDisk = typesFromDisk[i];
+ Type sourceType = types[i];
+ MethodInfo[] methodsFromDisk = typeFromDisk.IsValueType ? typeFromDisk.GetMethods(BindingFlags.DeclaredOnly) : typeFromDisk.GetMethods();
+ FieldInfo[] fieldsFromDisk = typeFromDisk.GetFields();
+
+ AssemblyTools.AssertTypeProperties(sourceType, typeFromDisk);
+ AssemblyTools.AssertMethods(sourceType.IsValueType ? sourceType.GetMethods(BindingFlags.DeclaredOnly) : sourceType.GetMethods(), methodsFromDisk);
+ AssemblyTools.AssertFields(sourceType.GetFields(), fieldsFromDisk);
+ ValidateAttributes(typeFromDisk.GetCustomAttributesData());
+
+ for (int j = 0; j < methodsFromDisk.Length; j++)
+ {
+ ValidateAttributes(methodsFromDisk[j].GetCustomAttributesData());
+ }
+
+ for (int j = 0; j < fieldsFromDisk.Length; j++)
+ {
+ ValidateAttributes(fieldsFromDisk[j].GetCustomAttributesData());
+ }
+ }
+ }
+ }
+
+ private void ValidateAttributes(IList<CustomAttributeData> attributesFromDisk)
+ {
+ Assert.Equal(_attributes.Count, attributesFromDisk.Count);
+
+ foreach (var attribute in attributesFromDisk)
+ {
+ if (attribute.AttributeType.Name == s_comVisibleType.Name)
+ {
+ Assert.Equal(s_comVisiblePair.con.MetadataToken, attribute.Constructor.MetadataToken);
+ Assert.Equal(s_comVisiblePair.args[0].GetType().FullName, attribute.ConstructorArguments[0].ArgumentType.FullName);
+ Assert.Equal(true, attribute.ConstructorArguments[0].Value);
+ }
+ else
+ {
+ Assert.Equal(s_guidPair.con.MetadataToken, attribute.Constructor.MetadataToken);
+ Assert.Equal(s_guidPair.args[0].GetType().FullName, attribute.ConstructorArguments[0].ArgumentType.FullName);
+ Assert.Equal(attribute.AttributeType.Name, s_guideType.Name);
+ Assert.Equal(s_guidPair.args[0], attribute.ConstructorArguments[0].Value);
+ }
+ }
+ }
+
+ private static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation, List<CustomAttributeBuilder>? assemblyAttributes = null,
+ List<CustomAttributeBuilder>? moduleAttributes = null, List<CustomAttributeBuilder>? typeAttributes = null,
+ List<CustomAttributeBuilder>? methodAttributes = null, List<CustomAttributeBuilder>? fieldAttributes = null)
+ {
+ AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(assemblyName, assemblyAttributes, typeof(string), out MethodInfo saveMethod);
+ ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
+ PopulateMembersForModule(mb, types, moduleAttributes, typeAttributes, methodAttributes, fieldAttributes);
+ saveMethod.Invoke(assemblyBuilder, new object[] { fileLocation });
+ }
+
+ private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types, List<CustomAttributeBuilder>? moduleAttributes,
+ List<CustomAttributeBuilder>? typeAttributes, List<CustomAttributeBuilder>? methodAttributes, List<CustomAttributeBuilder>? fieldAttributes)
+ {
+ if (moduleAttributes != null)
+ {
+ moduleAttributes.ForEach(mb.SetCustomAttribute);
+ }
+
+ foreach (Type type in types)
+ {
+ TypeBuilder tb = mb.DefineType(type.FullName, type.Attributes, type.BaseType);
+ typeAttributes.ForEach(tb.SetCustomAttribute);
+
+ DefineMethodsAndSetAttributes(methodAttributes, tb, type.IsInterface ? type.GetMethods() : type.GetMethods(BindingFlags.DeclaredOnly));
+ DefineFieldsAndSetAttributes(fieldAttributes, type.GetFields(), tb);
+ }
+ }
+
+ private static void DefineFieldsAndSetAttributes(List<CustomAttributeBuilder>? fieldAttributes, FieldInfo[] fields, TypeBuilder tb)
+ {
+ foreach (FieldInfo field in fields)
+ {
+ FieldBuilder fb = tb.DefineField(field.Name, field.FieldType, field.Attributes);
+ fieldAttributes.ForEach(fb.SetCustomAttribute);
+ }
+ }
+
+ private static void DefineMethodsAndSetAttributes(List<CustomAttributeBuilder> methodAttributes, TypeBuilder tb, MethodInfo[] methods)
+ {
+ foreach (var method in methods)
+ {
+ MethodBuilder meb = tb.DefineMethod(method.Name, method.Attributes, method.CallingConvention, method.ReturnType, null);
+ methodAttributes.ForEach(meb.SetCustomAttribute);
+ }
+ }
+
+ [Fact]
+ public void CreateStructWithPseudoCustomAttributesTest()
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ Type type = typeof(StructWithFields);
+ List<CustomAttributeBuilder> typeAttributes = new() { new CustomAttributeBuilder(typeof(SerializableAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(StructLayoutAttribute).GetConstructor(new Type[] { typeof(LayoutKind) }), new object[] { LayoutKind.Explicit },
+ typeof(StructLayoutAttribute).GetFields() , new object[]{32, 64, CharSet.Unicode}),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args),
+ new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { })
+ };
+ CustomAttributeBuilder[] fieldAttributes = new[] { new CustomAttributeBuilder(typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(FieldOffsetAttribute).GetConstructor(new Type[] { typeof(int) }), new object[] { 2 }),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args),
+ new CustomAttributeBuilder(typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(UnmanagedType) }), new object[] { UnmanagedType.I4}),
+ new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { })
+ };
+
+ AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
+ PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod);
+ TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes, type.BaseType);
+ DefineFieldsAndSetAttributes(fieldAttributes.ToList(), type.GetFields(), tb);
+ typeAttributes.ForEach(tb.SetCustomAttribute);
+ saveMethod.Invoke(ab, new object[] { file.Path });
+
+ Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
+ Module moduleFromDisk = assemblyFromDisk.Modules.First();
+ Type testType = moduleFromDisk.GetTypes()[0];
+ IList<CustomAttributeData> attributesFromDisk = testType.GetCustomAttributesData();
+
+ Assert.Equal(typeAttributes.Count - 3, attributesFromDisk.Count); // 3 pseudo attributes
+ Assert.True((testType.Attributes & TypeAttributes.Serializable) != 0); // SerializableAttribute
+ Assert.True((testType.Attributes & TypeAttributes.SpecialName) != 0); // SpecialNameAttribute
+ Assert.True((testType.Attributes & TypeAttributes.ExplicitLayout) != 0); // StructLayoutAttribute
+ Assert.True((testType.Attributes & TypeAttributes.UnicodeClass) != 0); // StructLayoutAttribute, not sure if we could test the PackingSize and Size
+
+ for (int i = 0; i < attributesFromDisk.Count; i++)
+ {
+ switch (attributesFromDisk[i].AttributeType.Name)
+ {
+ case "GuidAttribute":
+ Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value);
+ break;
+ default:
+ Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}");
+ break;
+ }
+ }
+
+ FieldInfo field = testType.GetFields()[0];
+ IList<CustomAttributeData> fieldAttributesFromDisk = field.GetCustomAttributesData();
+
+ Assert.Equal(3, fieldAttributesFromDisk.Count);
+ Assert.True((field.Attributes & FieldAttributes.NotSerialized) != 0); // NonSerializedAttribute
+ Assert.True((field.Attributes & FieldAttributes.SpecialName) != 0); // SpecialNameAttribute
+ Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute
+
+ for (int i = 0; i < fieldAttributesFromDisk.Count; i++)
+ {
+ switch (fieldAttributesFromDisk[i].AttributeType.Name)
+ {
+ case "FieldOffsetAttribute":
+ Assert.Equal(2, fieldAttributesFromDisk[i].ConstructorArguments[0].Value);
+ break;
+ case "MarshalAsAttribute":
+ Assert.Equal(UnmanagedType.I4, (UnmanagedType)fieldAttributesFromDisk[i].ConstructorArguments[0].Value);
+ break;
+ case "GuidAttribute":
+ Assert.Equal(s_guidPair.args[0], fieldAttributesFromDisk[i].ConstructorArguments[0].Value);
+ break;
+ default:
+ Assert.Fail($"Not expected attribute : {fieldAttributesFromDisk[i].AttributeType.Name}");
+ break;
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public void InterfacesWithPseudoCustomAttributes()
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ Type dllType = typeof(DllImportAttribute);
+ Type type = typeof(IMultipleMethod);
+ List<CustomAttributeBuilder> typeAttributes = new() { new CustomAttributeBuilder(typeof(ComImportAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(SuppressUnmanagedCodeSecurityAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args)
+ };
+ CustomAttributeBuilder[] methodAttributes = new[] { new CustomAttributeBuilder(typeof(PreserveSigAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(SuppressUnmanagedCodeSecurityAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args),
+ new CustomAttributeBuilder(typeof(MethodImplAttribute).GetConstructor(new Type[] { typeof(MethodImplOptions) }),
+ new object[] { MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization }),
+ new CustomAttributeBuilder(dllType.GetConstructor(new Type[] { typeof(string) }), new object[] { "test.dll" },
+ new FieldInfo[] { dllType.GetField("CharSet"), dllType.GetField("SetLastError"), dllType.GetField("CallingConvention"), dllType.GetField("BestFitMapping"),
+ dllType.GetField("ThrowOnUnmappableChar") }, new object[]{ CharSet.Ansi, true, CallingConvention.FastCall, true, false }),
+ };
+
+ AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
+ PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod);
+ TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes);
+ typeAttributes.ForEach(tb.SetCustomAttribute);
+ DefineMethodsAndSetAttributes(methodAttributes.ToList(), tb, type.GetMethods());
+ saveMethod.Invoke(ab, new object[] { file.Path });
+
+ Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
+ Type testType = assemblyFromDisk.Modules.First().GetTypes()[0];
+ IList<CustomAttributeData> attributesFromDisk = testType.GetCustomAttributesData();
+
+ Assert.Equal(typeAttributes.Count, attributesFromDisk.Count);
+ Assert.True((testType.Attributes & TypeAttributes.Import) != 0); // ComImportAttribute
+ Assert.True((testType.Attributes & TypeAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute
+ for (int i = 0; i < attributesFromDisk.Count; i++)
+ {
+ switch (attributesFromDisk[i].AttributeType.Name)
+ {
+ case "ComImportAttribute": // just making sure that these attributes are expected
+ case "SuppressUnmanagedCodeSecurityAttribute":
+ break;
+ case "GuidAttribute":
+ Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value);
+ break;
+ default:
+ Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}");
+ break;
+ }
+ }
+
+ foreach (var method in testType.GetMethods())
+ {
+ IList<CustomAttributeData> methodAttributesFromDisk = method.GetCustomAttributesData();
+
+ Assert.True((method.Attributes & MethodAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute
+ Assert.True((method.Attributes & MethodAttributes.SpecialName) != 0); // SpecialNameAttribute
+ MethodImplAttributes methodImpl = method.GetMethodImplementationFlags();
+ Assert.True((methodImpl & MethodImplAttributes.NoInlining) != 0); // MethodImplAttribute
+ Assert.True((methodImpl & MethodImplAttributes.AggressiveOptimization) != 0); // MethodImplAttribute
+ Assert.True((methodImpl & MethodImplAttributes.PreserveSig) != 0); // PreserveSigAttribute
+ Assert.Equal(methodAttributes.Length - 2, methodAttributesFromDisk.Count);
+
+ for (int i = 0; i < methodAttributesFromDisk.Count; i++)
+ {
+ switch (methodAttributesFromDisk[i].AttributeType.Name)
+ {
+ case "SuppressUnmanagedCodeSecurityAttribute":
+ case "PreserveSigAttribute":
+ break;
+ case "GuidAttribute":
+ Assert.Equal(s_guidPair.args[0], methodAttributesFromDisk[i].ConstructorArguments[0].Value);
+ break;
+ case "DllImportAttribute":
+ {
+ CustomAttributeData attribute = methodAttributesFromDisk[i];
+ Assert.Equal("test.dll", attribute.ConstructorArguments[0].Value);
+
+ for (int j = 0; j < attribute.NamedArguments.Count; j++)
+ {
+ switch (attribute.NamedArguments[j].MemberName)
+ {
+ case "CharSet":
+ Assert.Equal(CharSet.Ansi, (CharSet)attribute.NamedArguments[j].TypedValue.Value);
+ break;
+ case "SetLastError":
+ Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value);
+ break;
+ case "CallingConvention":
+ Assert.Equal(CallingConvention.FastCall, (CallingConvention)attribute.NamedArguments[j].TypedValue.Value);
+ break;
+ case "BestFitMapping":
+ Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value);
+ break;
+ case "ThrowOnUnmappableChar":
+ Assert.False((bool)attribute.NamedArguments[j].TypedValue.Value);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ Assert.Fail($"Not expected attribute : {methodAttributesFromDisk[i].AttributeType.Name}");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private static readonly ConstructorInfo marshalAsEnumCtor = typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(UnmanagedType) });
+ private static readonly ConstructorInfo marshalAsShortCtor = typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(short) });
+
+ public static IEnumerable<object[]> MarshalAsAttributeWithVariousFields()
+ {
+ yield return new object[] { new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.LPStr }), UnmanagedType.LPStr };
+ yield return new object[] { new CustomAttributeBuilder(marshalAsShortCtor, new object[] { (short)21 }), UnmanagedType.LPWStr };
+ yield return new object[] { new CustomAttributeBuilder(marshalAsShortCtor, new object[] { (short)19 }), UnmanagedType.BStr };
+ yield return new object[] { new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.ByValTStr },
+ new FieldInfo[] { typeof(MarshalAsAttribute).GetField("SizeConst") }, new object[] { 256 }) , UnmanagedType.ByValTStr };
+ yield return new object[] { new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.CustomMarshaler },
+ new FieldInfo[] { typeof(MarshalAsAttribute).GetField("MarshalType"), typeof(MarshalAsAttribute).GetField("MarshalCookie") },
+ new object[] { typeof(EmptyTestClass).AssemblyQualifiedName, "MyCookie" }) , UnmanagedType.CustomMarshaler };
+ // TODO: When array support added add test for LPArray/ByValArray/SafeArray
+ }
+
+ [Theory]
+ [MemberData(nameof(MarshalAsAttributeWithVariousFields))]
+ public void MarshalAsPseudoCustomAttributesTest(CustomAttributeBuilder attribute, UnmanagedType expectedType)
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ Type type = typeof(StructWithFields);
+ AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
+ PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod);
+ TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes, type.BaseType);
+ FieldInfo stringField = type.GetFields()[1];
+ FieldBuilder fb = tb.DefineField(stringField.Name, stringField.FieldType, stringField.Attributes);
+ fb.SetCustomAttribute(attribute);
+ saveMethod.Invoke(ab, new object[] { file.Path });
+
+ Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
+ FieldInfo field = assemblyFromDisk.Modules.First().GetTypes()[0].GetFields()[0];
+ CustomAttributeData attributeFromDisk = field.GetCustomAttributesData()[0];
+
+ Assert.Equal(1, field.GetCustomAttributesData().Count);
+ Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0);
+ Assert.Equal(expectedType, (UnmanagedType)attributeFromDisk.ConstructorArguments[0].Value);
+
+ switch (expectedType)
+ {
+ case UnmanagedType.CustomMarshaler:
+ Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName,
+ attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value);
+ Assert.Equal("MyCookie", attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalCookie").TypedValue.Value);
+ break;
+ case UnmanagedType.ByValTStr:
+ Assert.Equal(256, attributeFromDisk.NamedArguments.First(na => na.MemberName == "SizeConst").TypedValue.Value);
+ break;
+ }
+ }
+ }
+ }
+}
namespace System.Reflection.Emit.Tests
{
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
- public class AssemblySaveTestsWithVariousTypes
+ public class AssemblySaveWithVariousMembersTests
{
private static readonly AssemblyName s_assemblyName = new AssemblyName("MyDynamicAssembly")
{
using (TempFile file = TempFile.Create())
{
Assembly assemblyFromDisk = WriteAndLoadAssembly(Type.EmptyTypes, file.Path);
- AssemblyName aNameFromDisk = assemblyFromDisk.GetName();
-
- // Test AssemblyName properties
- Assert.Equal(s_assemblyName.Name, aNameFromDisk.Name);
- Assert.Equal(s_assemblyName.Version, aNameFromDisk.Version);
- Assert.Equal(s_assemblyName.CultureInfo, aNameFromDisk.CultureInfo);
- Assert.Equal(s_assemblyName.CultureName, aNameFromDisk.CultureName);
- Assert.Equal(s_assemblyName.ContentType, aNameFromDisk.ContentType);
- // Runtime assemblies adding AssemblyNameFlags.PublicKey in Assembly.GetName() overloads
- Assert.Equal(s_assemblyName.Flags | AssemblyNameFlags.PublicKey, aNameFromDisk.Flags);
- Assert.Empty(assemblyFromDisk.GetTypes());
-
- Module moduleFromDisk = assemblyFromDisk.Modules.FirstOrDefault();
- Assert.NotNull(moduleFromDisk);
- Assert.Equal(s_assemblyName.Name, moduleFromDisk.ScopeName);
- Assert.Empty(moduleFromDisk.GetTypes());
+ Assert.Empty(assemblyFromDisk.GetTypes());
+ AssemblyTools.AssertAssemblyNameAndModule(s_assemblyName, assemblyFromDisk.GetName(), assemblyFromDisk.Modules.FirstOrDefault());
}
}
Type sourceType = types[i];
Type typeFromDisk = typesFromDisk[i];
- AssertTypeProperties(sourceType, typeFromDisk);
- AssertMethods(sourceType.GetMethods(), typeFromDisk.GetMethods());
- AssertFields(sourceType.GetFields(), typeFromDisk.GetFields());
- }
- }
-
- private static void AssertFields(FieldInfo[] declaredFields, FieldInfo[] fieldsFromDisk)
- {
- Assert.Equal(declaredFields.Length, fieldsFromDisk.Length);
-
- for (int j = 0; j < declaredFields.Length; j++)
- {
- FieldInfo sourceField = declaredFields[j];
- FieldInfo fieldFromDisk = fieldsFromDisk[j];
-
- Assert.Equal(sourceField.Name, fieldFromDisk.Name);
- Assert.Equal(sourceField.Attributes, fieldFromDisk.Attributes);
- Assert.Equal(sourceField.FieldType.FullName, fieldFromDisk.FieldType.FullName);
+ AssemblyTools.AssertTypeProperties(sourceType, typeFromDisk);
+ AssemblyTools.AssertMethods(sourceType.GetMethods(), typeFromDisk.GetMethods());
+ AssemblyTools.AssertFields(sourceType.GetFields(), typeFromDisk.GetFields());
}
}
- private static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] methodsFromDisk)
- {
- Assert.Equal(sourceMethods.Length, methodsFromDisk.Length);
-
- for (int j = 0; j < sourceMethods.Length; j++)
- {
- MethodInfo sourceMethod = sourceMethods[j];
- MethodInfo methodFromDisk = methodsFromDisk[j];
-
- Assert.Equal(sourceMethod.Name, methodFromDisk.Name);
- Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes);
- Assert.Equal(sourceMethod.ReturnType.FullName, methodFromDisk.ReturnType.FullName);
- }
- }
-
- private static void AssertTypeProperties(Type sourceType, Type typeFromDisk)
- {
- Assert.Equal(sourceType.Name, typeFromDisk.Name);
- Assert.Equal(sourceType.Namespace, typeFromDisk.Namespace);
- Assert.Equal(sourceType.Attributes, typeFromDisk.Attributes);
- Assert.Equal(sourceType.IsInterface, typeFromDisk.IsInterface);
- Assert.Equal(sourceType.IsValueType, typeFromDisk.IsValueType);
- }
-
[Theory]
[MemberData(nameof(VariousInterfacesStructsTestData))]
public void WriteAssemblyWithVariousTypesToStreamAndReadBackTest(Type[] types)
{
using (TempFile file = TempFile.Create())
{
- MethodInfo defineDynamicAssemblyMethod = AssemblyTools.PopulateMethods(typeof(string), out MethodInfo saveMethod);
- AssemblyBuilder assemblyBuilder = (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null,
- new object[] { s_assemblyName, typeof(object).Assembly, null });
+ AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
+ s_assemblyName, null, typeof(string), out MethodInfo saveMethod);
ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");
TypeBuilder tb = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract);
using System.Collections.Generic;
using System.IO;
+using System.Runtime.InteropServices;
+using Xunit;
namespace System.Reflection.Emit.Tests
{
{
internal static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation)
{
- WriteAssemblyToDisk(assemblyName, types, fileLocation, null);
- }
-
- internal static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation, List<CustomAttributeBuilder> assemblyAttributes)
- {
- MethodInfo defineDynamicAssemblyMethod = PopulateMethods(typeof(string), out MethodInfo saveMethod);
+ AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilderAndSaveMethod(
+ assemblyName, null, typeof(string), out MethodInfo saveMethod);
- AssemblyBuilder assemblyBuilder = (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null,
- new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes });
ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
-
- PopulateMembersForModule(types, mb);
+ PopulateMembersForModule(mb, types);
saveMethod.Invoke(assemblyBuilder, new object[] { fileLocation });
}
- private static void PopulateMembersForModule(Type[] types, ModuleBuilder mb)
+ private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types)
{
foreach (Type type in types)
{
internal static void WriteAssemblyToStream(AssemblyName assemblyName, Type[] types, Stream stream)
{
- WriteAssemblyToStream(assemblyName, types, stream, null);
- }
-
- internal static void WriteAssemblyToStream(AssemblyName assemblyName, Type[] types, Stream stream, List<CustomAttributeBuilder>? assemblyAttributes)
- {
- MethodInfo defineDynamicAssemblyMethod = PopulateMethods(typeof(Stream), out MethodInfo saveMethod);
-
- AssemblyBuilder assemblyBuilder = (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null,
- new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes });
+ AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilderAndSaveMethod(
+ assemblyName, null, typeof(Stream), out MethodInfo saveMethod);
ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
-
- PopulateMembersForModule(types, mb);
+ PopulateMembersForModule(mb, types);
saveMethod.Invoke(assemblyBuilder, new object[] { stream });
}
- internal static MethodInfo PopulateMethods(Type parameterType, out MethodInfo saveMethod)
+ internal static AssemblyBuilder PopulateAssemblyBuilderAndSaveMethod(AssemblyName assemblyName,
+ List<CustomAttributeBuilder>? assemblyAttributes, Type parameterType, out MethodInfo saveMethod)
{
- Type assemblyType = Type.GetType(
- "System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit",
- throwOnError: true)!;
+ Type assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!;
saveMethod = assemblyType.GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance, new Type[] { parameterType });
- return assemblyType.GetMethod("DefinePersistedAssembly", BindingFlags.NonPublic | BindingFlags.Static,
+ MethodInfo defineDynamicAssemblyMethod = assemblyType.GetMethod("DefinePersistedAssembly", BindingFlags.NonPublic | BindingFlags.Static,
new Type[] { typeof(AssemblyName), typeof(Assembly), typeof(List<CustomAttributeBuilder>) });
+
+ return (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null,
+ new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes });
}
internal static Assembly LoadAssemblyFromPath(string filePath) =>
internal static Assembly LoadAssemblyFromStream(Stream stream) =>
new MetadataLoadContext(new CoreMetadataAssemblyResolver()).LoadFromStream(stream);
+
+ internal static void AssertAssemblyNameAndModule(AssemblyName sourceAName, AssemblyName aNameFromDisk, Module moduleFromDisk)
+ {
+ // Runtime assemblies adding AssemblyNameFlags.PublicKey in Assembly.GetName() overloads
+ Assert.Equal(sourceAName.Flags | AssemblyNameFlags.PublicKey, aNameFromDisk.Flags);
+ Assert.Equal(sourceAName.Name, aNameFromDisk.Name);
+ Assert.Equal(sourceAName.Version, aNameFromDisk.Version);
+ Assert.Equal(sourceAName.CultureInfo, aNameFromDisk.CultureInfo);
+ Assert.Equal(sourceAName.CultureName, aNameFromDisk.CultureName);
+ Assert.Equal(sourceAName.ContentType, aNameFromDisk.ContentType);
+
+ Assert.NotNull(moduleFromDisk);
+ Assert.Equal(sourceAName.Name, moduleFromDisk.ScopeName);
+ Assert.Empty(moduleFromDisk.GetTypes());
+ }
+
+ internal static void AssertTypeProperties(Type sourceType, Type typeFromDisk)
+ {
+ Assert.Equal(sourceType.Name, typeFromDisk.Name);
+ Assert.Equal(sourceType.Namespace, typeFromDisk.Namespace);
+ Assert.Equal(sourceType.Attributes, typeFromDisk.Attributes);
+ Assert.Equal(sourceType.IsInterface, typeFromDisk.IsInterface);
+ Assert.Equal(sourceType.IsValueType, typeFromDisk.IsValueType);
+ }
+
+ internal static void AssertFields(FieldInfo[] declaredFields, FieldInfo[] fieldsFromDisk)
+ {
+ Assert.Equal(declaredFields.Length, fieldsFromDisk.Length);
+
+ for (int j = 0; j < declaredFields.Length; j++)
+ {
+ FieldInfo sourceField = declaredFields[j];
+ FieldInfo fieldFromDisk = fieldsFromDisk[j];
+
+ Assert.Equal(sourceField.Name, fieldFromDisk.Name);
+ Assert.Equal(sourceField.Attributes, fieldFromDisk.Attributes);
+ Assert.Equal(sourceField.FieldType.FullName, fieldFromDisk.FieldType.FullName);
+ }
+ }
+
+ internal static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] methodsFromDisk)
+ {
+ Assert.Equal(sourceMethods.Length, methodsFromDisk.Length);
+
+ for (int j = 0; j < sourceMethods.Length; j++)
+ {
+ MethodInfo sourceMethod = sourceMethods[j];
+ MethodInfo methodFromDisk = methodsFromDisk[j];
+
+ Assert.Equal(sourceMethod.Name, methodFromDisk.Name);
+ Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes);
+ Assert.Equal(sourceMethod.ReturnType.FullName, methodFromDisk.ReturnType.FullName);
+ }
+ }
}
// The resolver copied from MLC tests
<Compile Include="ModuleBuilder\ModuleBuilderGetArrayMethod.cs" />
<Compile Include="ModuleBuilder\ModuleBuilderSetCustomAttribute.cs" />
<Compile Include="ParameterBuilder\ParameterBuilderSetConstant.cs" />
- <Compile Include="PersistableAssemblyBuilder\AssemblySaveTestsWithVariousTypes.cs" />
+ <Compile Include="PersistableAssemblyBuilder\AssemblySaveCustomAttributeTests.cs" />
+ <Compile Include="PersistableAssemblyBuilder\AssemblySaveWithVariousMembersTests.cs" />
<Compile Include="PersistableAssemblyBuilder\AssemblyTools.cs" />
<Compile Include="PropertyBuilder\PropertyBuilderAddOtherMethod.cs" />
<Compile Include="PropertyBuilder\PropertyBuilderAttributes.cs" />
return result;
}
- internal CustomAttributeBuilder(ConstructorInfo con, byte[] binaryAttribute)
+ internal CustomAttributeBuilder(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
ArgumentNullException.ThrowIfNull(con);
- ArgumentNullException.ThrowIfNull(binaryAttribute);
ctor = con;
- data = (byte[])binaryAttribute.Clone();
+ data = binaryAttribute.ToArray();
/* should we check that the user supplied data is correct? */
}
}
/* helper methods */
- internal static int decode_len(byte[] data, int pos, out int rpos)
+ internal static int decode_len(ReadOnlySpan<byte> data, int pos, out int rpos)
{
int len;
if ((data[pos] & 0x80) == 0)
return len;
}
- internal static string string_from_bytes(byte[] data, int pos, int len)
+ internal static string string_from_bytes(ReadOnlySpan<byte> data, int pos, int len)
{
- return Text.Encoding.UTF8.GetString(data, pos, len);
+ return Text.Encoding.UTF8.GetString(data.Slice(pos, len));
}
internal static string? decode_string(byte[] data, int pos, out int rpos)
_ => throw new Exception(SR.Format(SR.ArgumentException_InvalidTypeArgument, elementType)),
};
- private static object? decode_cattr_value(Type t, byte[] data, int pos, out int rpos)
+ private static object? decode_cattr_value(Type t, ReadOnlySpan<byte> data, int pos, out int rpos)
{
switch (Type.GetTypeCode(t))
{
public object?[] namedParamValues;
}
+ internal static CustomAttributeInfo decode_cattr(CustomAttributeBuilder customBuilder)
+ {
+ byte[] data = customBuilder.Data;
+ ConstructorInfo ctor = customBuilder.Ctor;
+ return decode_cattr(ctor, data);
+ }
+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2057:UnrecognizedReflectionPattern",
Justification = "Types referenced from custom attributes are preserved")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern",
Justification = "Types referenced from custom attributes are preserved")]
- internal static CustomAttributeInfo decode_cattr(CustomAttributeBuilder customBuilder)
+ internal static CustomAttributeInfo decode_cattr(ConstructorInfo ctor, ReadOnlySpan<byte> data)
{
- byte[] data = customBuilder.Data;
- ConstructorInfo ctor = customBuilder.Ctor;
int pos;
CustomAttributeInfo info = default;
public override bool IsCollectible => access == (uint)AssemblyBuilderAccess.RunAndCollect;
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
UpdateNativeCustomAttributes(this);
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
/*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
internal static Type MakeGenericType(Type gtd, Type[] typeArguments) =>
new TypeBuilderInstantiation(gtd, typeArguments);
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
+using System.Buffers.Binary;
namespace System.Reflection.Emit
{
return ilgen;
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
- ArgumentNullException.ThrowIfNull(customBuilder);
-
- string? attrname = customBuilder.Ctor.ReflectedType!.FullName;
+ string? attrname = con.ReflectedType!.FullName;
if (attrname == "System.Runtime.CompilerServices.MethodImplAttribute")
{
- byte[] data = customBuilder.Data;
- int impla; // the (stupid) ctor takes a short or an int ...
- impla = (int)data[2];
- impla |= ((int)data[3]) << 8;
+ int impla = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2));
SetImplementationFlags((MethodImplAttributes)impla);
return;
}
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- ArgumentNullException.ThrowIfNull(con);
- ArgumentNullException.ThrowIfNull(binaryAttribute);
-
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
{
if (type.is_created)
return SymbolType.FormCompoundType("*", this, 0)!;
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
- _tb.SetCustomAttribute(customBuilder);
- }
-
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
+ _tb.SetCustomAttribute(con, binaryAttribute);
}
internal override bool IsUserType
remove_method = mdBuilder;
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
RejectIfCreated();
- string? attrname = customBuilder.Ctor.ReflectedType!.FullName;
+ string? attrname = con.ReflectedType!.FullName;
if (attrname == "System.Runtime.CompilerServices.SpecialNameAttribute")
{
attrs |= EventAttributes.SpecialName;
return;
}
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
private void RejectIfCreated()
{
if (typeb.is_created)
using System.Globalization;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
+using System.Buffers.Binary;
namespace System.Reflection.Emit
{
def_value = defaultValue;
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
RejectIfCreated();
-
- string? attrname = customBuilder.Ctor.ReflectedType!.FullName;
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
+ string? attrname = con.ReflectedType!.FullName;
if (attrname == "System.Runtime.InteropServices.FieldOffsetAttribute")
{
- byte[] data = customBuilder.Data;
- offset = (int)data[2];
- offset |= ((int)data[3]) << 8;
- offset |= ((int)data[4]) << 16;
- offset |= ((int)data[5]) << 24;
+ offset = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(2));
return;
}
#pragma warning disable SYSLIB0050 // FieldAttributes.NotSerialized is obsolete
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- RejectIfCreated();
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
protected override void SetOffsetCore(int iOffset)
{
RejectIfCreated();
get { return mbuilder; }
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
}
}
- // FIXME: "unverified implementation"
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
private static NotSupportedException not_supported()
{
return new NotSupportedException();
//
#if MONO_FEATURE_SRE
+using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
}
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
- switch (customBuilder.Ctor.ReflectedType!.FullName)
+ switch (con.ReflectedType!.FullName)
{
case "System.Runtime.CompilerServices.MethodImplAttribute":
- byte[] data = customBuilder.Data;
- int impla; // the (stupid) ctor takes a short or an int ...
- impla = (int)data[2];
- impla |= ((int)data[3]) << 8;
+ int impla = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2));
iattrs |= (MethodImplAttributes)impla;
return;
case "System.Runtime.InteropServices.DllImportAttribute":
- CustomAttributeBuilder.CustomAttributeInfo attr = CustomAttributeBuilder.decode_cattr(customBuilder);
+ CustomAttributeBuilder.CustomAttributeInfo attr = CustomAttributeBuilder.decode_cattr(con, binaryAttribute);
bool preserveSig = true;
/*
break;
}
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
{
RejectIfCreated();
return index;
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
cattrs[0] = customBuilder;
}
}
-
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
/*
internal ISymbolDocumentWriter? DefineDocument (string url, Guid language, Guid languageVendor, Guid documentType)
{
def_value = defaultValue;
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
typeb.check_not_created();
- string? attrname = customBuilder.Ctor.ReflectedType!.FullName;
+ string? attrname = con.ReflectedType!.FullName;
if (attrname == "System.Runtime.CompilerServices.SpecialNameAttribute")
{
attrs |= PropertyAttributes.SpecialName;
return;
}
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
+
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
protected override void SetGetMethodCore(MethodBuilder mdBuilder)
{
typeb.check_not_created();
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
}
}
- protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
+ internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
- string? attrname = customBuilder.Ctor.ReflectedType!.FullName;
+ SetCustomAttributeCore(con, binaryAttribute);
+ }
+
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
+ {
+ string? attrname = con.ReflectedType!.FullName;
if (attrname == "System.Runtime.InteropServices.StructLayoutAttribute")
{
- byte[] data = customBuilder.Data;
int layout_kind; /* the (stupid) ctor takes a short or an int ... */
- layout_kind = (int)data[2];
- layout_kind |= ((int)data[3]) << 8;
+ layout_kind = (int)binaryAttribute[2];
+ layout_kind |= ((int)binaryAttribute[3]) << 8;
attrs &= ~TypeAttributes.LayoutMask;
attrs |= ((LayoutKind)layout_kind) switch
{
_ => throw new Exception(SR.Argument_InvalidKindOfTypeForCA), // we should ignore it since it can be any value anyway...
};
- Type ctor_type = customBuilder.Ctor is RuntimeConstructorBuilder builder ? builder.parameters![0] : customBuilder.Ctor.GetParametersInternal()[0].ParameterType;
+ Type ctor_type = con is RuntimeConstructorBuilder builder ? builder.parameters![0] : con.GetParametersInternal()[0].ParameterType;
int pos = 6;
if (ctor_type.FullName == "System.Int16")
pos = 4;
- int nnamed = (int)data[pos++];
- nnamed |= ((int)data[pos++]) << 8;
+ int nnamed = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(pos++));
+ pos++;
for (int i = 0; i < nnamed; ++i)
{
//byte named_type = data [pos++];
pos++;
- byte type = data[pos++];
+ byte type = binaryAttribute[pos++];
int len;
string named_name;
if (type == 0x55)
{
- len = CustomAttributeBuilder.decode_len(data, pos, out pos);
+ len = CustomAttributeBuilder.decode_len(binaryAttribute, pos, out pos);
//string named_typename =
- CustomAttributeBuilder.string_from_bytes(data, pos, len);
+ CustomAttributeBuilder.string_from_bytes(binaryAttribute, pos, len);
pos += len;
// FIXME: Check that 'named_type' and 'named_typename' match, etc.
// See related code/FIXME in mono/mono/metadata/reflection.c
}
- len = CustomAttributeBuilder.decode_len(data, pos, out pos);
- named_name = CustomAttributeBuilder.string_from_bytes(data, pos, len);
+ len = CustomAttributeBuilder.decode_len(binaryAttribute, pos, out pos);
+ named_name = CustomAttributeBuilder.string_from_bytes(binaryAttribute, pos, len);
pos += len;
/* all the fields are integers in StructLayout */
- int value = (int)data[pos++];
- value |= ((int)data[pos++]) << 8;
- value |= ((int)data[pos++]) << 16;
- value |= ((int)data[pos++]) << 24;
+ int value = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(pos++));
+ pos += 3;
switch (named_name)
{
case "CharSet":
is_byreflike_set = 1;
}
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
+
if (cattrs != null)
{
CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1];
}
}
- protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute));
- }
-
protected override EventBuilder DefineEventCore(string name, EventAttributes attributes, Type eventtype)
{
check_name(nameof(name), name);