Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
wasabii committed Oct 13, 2024
1 parent 2daab5a commit b7b2716
Show file tree
Hide file tree
Showing 132 changed files with 1,662 additions and 3,248 deletions.
79 changes: 60 additions & 19 deletions src/IKVM.CoreLib.Tests/Symbols/Reflection/ReflectionSymbolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,38 @@ public class ReflectionSymbolTests
class Foo<T>
{
T? field;
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
class AttributeWithWithDefaultCtor : Attribute
{

public AttributeWithWithDefaultCtor()
{

}

}

[AttributeUsage(AttributeTargets.Class)]
class AttributeWithType : Attribute
{

public AttributeWithType(Type type)
{
Type = type;
}

public Type Type { get; }

}

[AttributeWithType(typeof(object))]
class ClassWithAttributeWithType
{



}

[TestMethod]
Expand Down Expand Up @@ -183,35 +215,44 @@ public void CanResolveParameters()
p[1].ParameterType.Should().Be(c.GetOrCreateTypeSymbol(typeof(object)));
}

[AttributeUsage(AttributeTargets.Class)]
class AttributeWithType : Attribute
[TestMethod]
public void CanReadCustomAttributes()
{

public AttributeWithType(Type type)
{
Type = type;
}

public Type Type { get; }

var c = new ReflectionSymbolContext();
var s = c.GetOrCreateTypeSymbol(typeof(ClassWithAttributeWithType));
var a = s.GetCustomAttribute(c.GetOrCreateTypeSymbol(typeof(AttributeWithType)));
var v = a.Value.ConstructorArguments[0].Value;
v.Should().BeOfType<ReflectionTypeSymbol>();
}

[AttributeWithType(typeof(object))]
class ClassWithAttributeWithType
[TestMethod]
public void CanReadCustomAttributesFromTypeBuilder()
{
var c = new ReflectionSymbolContext();
var a = c.DefineAssembly(new AssemblyIdentity("DynamicAssembly"), false, false);
var m = a.DefineModule("DynamicModule");
var type = m.DefineType("DynamicType");



type.SetCustomAttribute(CustomAttribute.Create(c.GetOrCreateTypeSymbol(typeof(AttributeWithWithDefaultCtor)).GetConstructors()[0], []));
var ca = type.GetCustomAttribute(c.GetOrCreateTypeSymbol(typeof(AttributeWithWithDefaultCtor)));
ca.Should().NotBeNull();
}

[TestMethod]
public void CanReadCustomAttributes()
public void CanReadCustomAttributesFromMethodBuilder()
{
var c = new ReflectionSymbolContext();
var s = c.GetOrCreateTypeSymbol(typeof(ClassWithAttributeWithType));
var a = s.GetCustomAttribute(c.GetOrCreateTypeSymbol(typeof(AttributeWithType)));
var v = a.Value.ConstructorArguments[0].Value;
v.Should().BeOfType<ReflectionTypeSymbol>();
var a = c.DefineAssembly(new AssemblyIdentity("DynamicAssembly"), false, false);
var m = a.DefineModule("DynamicModule");
var type = m.DefineType("DynamicType");

var method = type.DefineMethod("DynamicMethod1", System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ret);

method.SetCustomAttribute(CustomAttribute.Create(c.GetOrCreateTypeSymbol(typeof(AttributeWithWithDefaultCtor)).GetConstructors()[0], []));
var ca = method.GetCustomAttribute(c.GetOrCreateTypeSymbol(typeof(AttributeWithWithDefaultCtor)));
ca.Should().NotBeNull();
}

[TestMethod]
Expand Down
75 changes: 75 additions & 0 deletions src/IKVM.CoreLib/Reflection/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
Expand Down Expand Up @@ -590,6 +591,80 @@ public static bool IsSZArray(this Type type)
#endif
}

/// <summary>
/// Implements GetcustomAttributeData with support for examining inheritence.
/// </summary>
/// <returns></returns>
public static IEnumerable<CustomAttributeData> GetCustomAttributesData(this Type type, bool inherit)
{
foreach (var i in type.GetCustomAttributesData())
yield return i;

if (inherit)
for (var baseType = type.BaseType; baseType != null; baseType = baseType.BaseType)
foreach (var cad in baseType.GetCustomAttributesData())
if (cad.AttributeType.GetCustomAttribute<AttributeUsageAttribute>()?.Inherited ?? false)
yield return cad;
}

/// <summary>
/// Implements GetcustomAttributeData with support for examining inheritence.
/// </summary>
/// <returns></returns>
public static IEnumerable<CustomAttributeData> GetInheritedCustomAttributesData(this Type type)
{
for (var baseType = type.BaseType; baseType != null; baseType = baseType.BaseType)
foreach (var cad in baseType.GetCustomAttributesData())
if (cad.AttributeType.GetCustomAttribute<AttributeUsageAttribute>()?.Inherited ?? false)
yield return cad;
}

/// <summary>
/// Implements GetcustomAttributeData with support for examining inheritence.
/// </summary>
/// <param name="inherit"></param>
/// <returns></returns>
public static IEnumerable<CustomAttributeData> GetCustomAttributesData(this MethodInfo method, bool inherit)
{
foreach (var i in method.GetCustomAttributesData())
yield return i;

if (inherit)
for (var baseMethod = method.GetBaseDefinition(); baseMethod != null; baseMethod = baseMethod.GetBaseDefinition())
foreach (var cad in baseMethod.GetCustomAttributesData())
if (cad.AttributeType.GetCustomAttribute<AttributeUsageAttribute>()?.Inherited ?? false)
yield return cad;
}

/// <summary>
/// Implements GetcustomAttributeData with support for examining inheritence.
/// </summary>
/// <param name="inherit"></param>
/// <returns></returns>
public static IEnumerable<CustomAttributeData> GetInheritedCustomAttributesData(this MethodInfo method)
{
for (var baseMethod = method.GetBaseDefinition(); baseMethod != null; baseMethod = baseMethod.GetBaseDefinition())
foreach (var cad in baseMethod.GetCustomAttributesData())
if (cad.AttributeType.GetCustomAttribute<AttributeUsageAttribute>()?.Inherited ?? false)
yield return cad;
}

/// <summary>
/// Implements GetcustomAttributeData with support for examining inheritence.
/// </summary>
/// <param name="inherit"></param>
/// <returns></returns>
public static IEnumerable<CustomAttributeData> GetCustomAttributesData(this MemberInfo member, bool inherit)
{
if (member is Type type)
return GetCustomAttributesData(type, inherit);

if (member is MethodInfo method)
return GetCustomAttributesData(method, inherit);

return member.GetCustomAttributesData();
}

}

}
148 changes: 146 additions & 2 deletions src/IKVM.CoreLib/Symbols/CustomAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Immutable;
using System;
using System.Collections.Immutable;
using System.Linq;

namespace IKVM.CoreLib.Symbols
{
Expand All @@ -7,7 +9,149 @@ readonly record struct CustomAttribute(
ITypeSymbol AttributeType,
IConstructorSymbol Constructor,
ImmutableArray<CustomAttributeTypedArgument> ConstructorArguments,
ImmutableArray<CustomAttributeNamedArgument> NamedArguments);
ImmutableArray<CustomAttributeNamedArgument> NamedArguments)
{

/// <summary>
/// Initializes an instance of the <see cref="CustomAttribute"/> interface given the constructor for the custom attribute and the arguments to the constructor.
/// </summary>
/// <param name="ctor"></param>
/// <param name="constructorArgs"></param>
/// <returns></returns>
public static CustomAttribute Create(IConstructorSymbol ctor, object?[] constructorArgs)
{
return new CustomAttribute(
ctor.DeclaringType ?? throw new InvalidOperationException(),
ctor,
PackTypedArgs(ctor.GetParameters().Select(i => i.ParameterType).ToArray(), constructorArgs),
ImmutableArray<CustomAttributeNamedArgument>.Empty);
}

/// <summary>
/// Initializes an instance of the <see cref="CustomAttribute"/> interface given the constructor for the custom attribute, the arguments to the constructor, and a set of named field/value pairs.
/// </summary>
/// <param name="ctor"></param>
/// <param name="constructorArgs"></param>
/// <param name="namedFields"></param>
/// <param name="fieldValues"></param>
public static CustomAttribute Create(IConstructorSymbol ctor, object?[] constructorArgs, IFieldSymbol[] namedFields, object?[] fieldValues)
{
return new CustomAttribute(
ctor.DeclaringType ?? throw new InvalidOperationException(),
ctor,
PackTypedArgs(ctor.GetParameters().Select(i => i.ParameterType).ToArray(), constructorArgs),
PackNamedArgs([], [], namedFields, fieldValues));
}

/// <summary>
/// Initializes an instance of the <see cref="CustomAttribute"/> interface given the constructor for the custom attribute, the arguments to the constructor, and a set of named property or value pairs.
/// </summary>
/// <param name="ctor"></param>
/// <param name="constructorArgs"></param>
/// <param name="namedProperties"></param>
/// <param name="propertyValues"></param>
public static CustomAttribute Create(IConstructorSymbol ctor, object?[] constructorArgs, IPropertySymbol[] namedProperties, object?[] propertyValues)
{
return new CustomAttribute(
ctor.DeclaringType ?? throw new InvalidOperationException(),
ctor,
PackTypedArgs(ctor.GetParameters().Select(i => i.ParameterType).ToArray(), constructorArgs),
PackNamedArgs(namedProperties, propertyValues, [], []));
}

/// <summary>
/// Initializes an instance of the <see cref="CustomAttribute"/> interface given the constructor for the custom attribute, the arguments to the constructor, a set of named property or value pairs, and a set of named field or value pairs.
/// </summary>
/// <param name="ctor"></param>
/// <param name="constructorArgs"></param>
/// <param name="namedProperties"></param>
/// <param name="propertyValues"></param>
/// <param name="namedFields"></param>
/// <param name="fieldValues"></param>
public static CustomAttribute Create(IConstructorSymbol ctor, object?[] constructorArgs, IPropertySymbol[] namedProperties, object?[] propertyValues, IFieldSymbol[] namedFields, object?[] fieldValues)
{
return new CustomAttribute(
ctor.DeclaringType ?? throw new InvalidOperationException(),
ctor,
PackTypedArgs(ctor.GetParameters().Select(i => i.ParameterType).ToArray(), constructorArgs),
PackNamedArgs(namedProperties, propertyValues, namedFields, fieldValues));
}

/// <summary>
/// Packs the types as typed arguments.
/// </summary>
/// <param name="types"></param>
/// <param name="values"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
static ImmutableArray<CustomAttributeTypedArgument> PackTypedArgs(ITypeSymbol[] types, object?[] values)
{
if (types is null)
throw new ArgumentNullException(nameof(types));
if (values is null)
throw new ArgumentNullException(nameof(values));
if (types.Length != values.Length)
throw new ArgumentException();

var a = ImmutableArray.CreateBuilder<CustomAttributeTypedArgument>(types.Length);
for (int i = 0; i < types.Length; i++)
a.Add(PackTypedArg(types[i], values[i]));

return a.ToImmutable();
}

/// <summary>
/// Packs the type as a typed argument.
/// </summary>
/// <param name="type"></param>
/// <param name="value"></param>
/// <returns></returns>
static CustomAttributeTypedArgument PackTypedArg(ITypeSymbol type, object? value)
{
return new CustomAttributeTypedArgument(type, value);
}

/// <summary>
/// Packages the members and args as a named argument.
/// </summary>
/// <param name="namedProperties"></param>
/// <param name="propertyValues"></param>
/// <returns></returns>
static ImmutableArray<CustomAttributeNamedArgument> PackNamedArgs(IPropertySymbol[] namedProperties, object?[] propertyValues, IFieldSymbol[] namedFields, object?[] fieldValues)
{
var a = ImmutableArray.CreateBuilder<CustomAttributeNamedArgument>(namedProperties.Length + namedFields.Length);
for (int i = 0; i < namedProperties.Length; i++)
a.Add(PackNamedArg(namedProperties[i], propertyValues[i]));
for (int i = 0; i < namedFields.Length; i++)
a.Add(PackNamedArg(namedFields[i], fieldValues[i]));

return a.ToImmutable();
}

/// <summary>
/// Packs the property and arg as a named argument.
/// </summary>
/// <param name="property"></param>
/// <param name="v"></param>
/// <returns></returns>
static CustomAttributeNamedArgument PackNamedArg(IPropertySymbol property, object? v)
{
return new CustomAttributeNamedArgument(false, property, property.Name, PackTypedArg(property.PropertyType, v));
}

/// <summary>
/// Packs the field and arg as a named argument.
/// </summary>
/// <param name="field"></param>
/// <param name="v"></param>
/// <returns></returns>
static CustomAttributeNamedArgument PackNamedArg(IFieldSymbol field, object? v)
{
return new CustomAttributeNamedArgument(false, field, field.Name, PackTypedArg(field.FieldType, v));
}

}


}
15 changes: 1 addition & 14 deletions src/IKVM.CoreLib/Symbols/Emit/IAssemblySymbolBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace IKVM.CoreLib.Symbols.Emit
{

interface IAssemblySymbolBuilder : ISymbolBuilder<IAssemblySymbol>, IAssemblySymbol
interface IAssemblySymbolBuilder : ISymbolBuilder<IAssemblySymbol>, IAssemblySymbol, ICustomAttributeProviderBuilder
{

/// <summary>
Expand All @@ -30,19 +30,6 @@ interface IAssemblySymbolBuilder : ISymbolBuilder<IAssemblySymbol>, IAssemblySym
/// <returns></returns>
IModuleSymbolBuilder DefineModule(string name, string fileName, bool emitSymbolInfo);

/// <summary>
/// Set a custom attribute using a custom attribute builder.
/// </summary>
/// <param name="customBuilder"></param>
void SetCustomAttribute(ICustomAttributeBuilder customBuilder);

/// <summary>
/// Sets a custom attribute using a specified custom attribute blob.
/// </summary>
/// <param name="con"></param>
/// <param name="binaryAttribute"></param>
void SetCustomAttribute(IConstructorSymbol con, byte[] binaryAttribute);

/// <summary>
/// Sets a Win32 icon on the generated assembly.
/// </summary>
Expand Down
11 changes: 0 additions & 11 deletions src/IKVM.CoreLib/Symbols/Emit/ICustomAttributeBuilder.cs

This file was deleted.

Loading

0 comments on commit b7b2716

Please sign in to comment.