Skip to content

Commit

Permalink
Adding support to enums
Browse files Browse the repository at this point in the history
Reflection to support enums.
Added tests.

Targets #41
  • Loading branch information
andry-tino committed Jun 8, 2017
1 parent 24c6eef commit f35e782
Show file tree
Hide file tree
Showing 24 changed files with 745 additions and 60 deletions.
2 changes: 2 additions & 0 deletions src/Reflection.ScriptSharp/ProgramWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ namespace Rosetta.Reflection.ScriptSharp
/// </summary>
public class ProgramWrapper : Rosetta.Reflection.ProgramWrapper
{
// TODO: Rename this whole assembly into Reflection.ScriptSharp.Definition

/// <summary>
/// Initializes a new instance of the <see cref="ProgramWrapper"/> class.
/// </summary>
Expand Down
21 changes: 14 additions & 7 deletions src/Reflection/ASTBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,17 @@ private ASTInfo BuildASTInfo()
var numberOfEnums = 0;
var numberOfStructs = 0;

// Some types, like enum, are identified in metadata as classes inheriting from
// System.Enum, so we need to pay attention to that
foreach (var type in types)
{
if (type.IsClass) { nodes.Add(this.BuildClassNode(type)); numberOfClasses++; continue; }
if (type.IsNativeClassType()) { nodes.Add(this.BuildClassNode(type)); numberOfClasses++; continue; }

if (type.IsValueType) { nodes.Add(this.BuildStructNode(type)); numberOfStructs++; continue; }
if (type.IsNativeStructType()) { nodes.Add(this.BuildStructNode(type)); numberOfStructs++; continue; }

if (type.IsInterface) { nodes.Add(this.BuildInterfaceNode(type)); numberOfInterfaces++; continue; }

if (type.IsEnum) { nodes.Add(this.BuildEnumNode(type)); numberOfEnums++; continue; }
if (type.IsNativeEnumType()) { nodes.Add(this.BuildEnumNode(type)); numberOfEnums++; continue; }
}

// Use collected nodes to build a tree containing them all in the root.
Expand All @@ -98,7 +100,7 @@ private ASTInfo BuildASTInfo()
{
Tree = tree,
SemanticModel = this.RetrieveSemanticModel(tree),
ClassCount = numberOfStructs,
ClassCount = numberOfClasses,
InterfaceCount = numberOfInterfaces,
EnumCount = numberOfEnums,
StructCount = numberOfStructs
Expand All @@ -118,8 +120,7 @@ private MemberDeclarationSyntax BuildStructNode(ITypeInfoProxy type)

private MemberDeclarationSyntax BuildEnumNode(ITypeInfoProxy type)
{
// TODO
return this.BuildNode(type, SyntaxFactory.EnumDeclaration);
return this.BuildNode(type, this.BuildEnumNodeCore(type));
}

private MemberDeclarationSyntax BuildInterfaceNode(ITypeInfoProxy type)
Expand Down Expand Up @@ -148,7 +149,13 @@ private MemberDeclarationSyntax BuildInterfaceNodeCore(ITypeInfoProxy type)
return new InterfaceDeclarationSyntaxFactory(type).Create() as MemberDeclarationSyntax;
}

// TODO: Remove this once all core methods have been built
private MemberDeclarationSyntax BuildEnumNodeCore(ITypeInfoProxy type)
{
return new EnumDeclarationSyntaxFactory(type).Create() as MemberDeclarationSyntax;
}

// TODO: Remove this once all core methods have been built.
// This thing only generates the Roslyn node without any further processing
private MemberDeclarationSyntax BuildNode(ITypeInfoProxy type, RoslynNodeFactory factory)
{
var helper = this.CreateNamespaceHelper(type);
Expand Down
9 changes: 9 additions & 0 deletions src/Reflection/ASTInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,14 @@ public class ASTInfo
/// Gets or sets the number of generated interfaces.
/// </summary>
public int InterfaceCount { get; set; }

/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"classes={this.ClassCount}, interfaces={this.InterfaceCount}, enums={this.EnumCount}, structs={this.StructCount}";
}
}
}
2 changes: 1 addition & 1 deletion src/Reflection/ProgramWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private void Initialize()
this.output = this.walker.Walk().Translate();

// Some info
this.info = $"AST generation: classes={astInfo.ClassCount}, interfaces={astInfo.InterfaceCount}, enums={astInfo.EnumCount}, structs={astInfo.StructCount}";
this.info = $"AST generation: {astInfo.ToString()}";

this.initialized = true;
}
Expand Down
8 changes: 8 additions & 0 deletions src/Reflection/Reflection.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
<Compile Include="assembly-proxying\IConstructorInfoProxy.cs" />
<Compile Include="assembly-proxying\ICustomAttributeDataProxy.cs" />
<Compile Include="assembly-proxying\ICustomAttributeTypedArgumentProxy.cs" />
<Compile Include="assembly-proxying\IFieldInfoProxy.cs" />
<Compile Include="assembly-proxying\IMethodBaseProxy.cs" />
<Compile Include="assembly-proxying\IMethodInfoProxy.cs" />
<Compile Include="assembly-proxying\IParameterInfoProxy.cs" />
Expand All @@ -135,6 +136,7 @@
<Compile Include="assembly-proxying\mono\MonoConstructorInfoProxy.cs" />
<Compile Include="assembly-proxying\mono\MonoCustomAttributeDataProxy.cs" />
<Compile Include="assembly-proxying\mono\MonoCustomAttributeTypedArgumentProxy.cs" />
<Compile Include="assembly-proxying\mono\MonoFieldInfoProxy.cs" />
<Compile Include="assembly-proxying\mono\MonoMethodBaseProxy.cs" />
<Compile Include="assembly-proxying\mono\MonoMethodInfoProxy.cs" />
<Compile Include="assembly-proxying\mono\MonoParameterInfoProxy.cs" />
Expand All @@ -145,11 +147,16 @@
<Compile Include="ASTInfo.cs" />
<Compile Include="factories\ClassDeclarationSyntaxFactory.cs" />
<Compile Include="factories\ConstructorDeclarationSyntaxFactory.cs" />
<Compile Include="factories\EnumDeclarationSyntaxFactory.cs" />
<Compile Include="factories\FieldDeclarationSyntaxFactory.cs" />
<Compile Include="factories\InterfaceDeclarationSyntaxFactory.cs" />
<Compile Include="factories\ISyntaxFactory.cs" />
<Compile Include="factories\MethodDeclarationSyntaxFactory.cs" />
<Compile Include="factories\PropertyDeclarationSyntaxFactory.cs" />
<Compile Include="helpers\EnumClass.cs" />
<Compile Include="helpers\NativeClass.cs" />
<Compile Include="helpers\ObjectClass.cs" />
<Compile Include="helpers\ValueTypeClass.cs" />
<Compile Include="helpers\Visibility.cs" />
<Compile Include="loading\MonoFSAssemblyLoader.cs" />
<Compile Include="helpers\Namespace.cs" />
Expand All @@ -159,6 +166,7 @@
<Compile Include="ProgramWrapper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="utilities\DummyBody.cs" />
<Compile Include="utilities\NativeTypes.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
Expand Down
41 changes: 41 additions & 0 deletions src/Reflection/assembly-proxying/IFieldInfoProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/// <summary>
/// IFieldInfoProxy.cs
/// Andrea Tino - 2017
/// </summary>

namespace Rosetta.Reflection.Proxies
{
using System;

/// <summary>
/// Abstracts field info API.
/// </summary>
public interface IFieldInfoProxy
{
/// <summary>
/// Gets the name of the current member.
/// </summary>
string Name { get; }

/// <summary>
/// Gets the Type of this field.
/// </summary>
ITypeProxy FieldType { get; }

/// <summary>
/// Gets a value indicating whether the field is visible only within its class
/// and derived classes.
/// </summary>
bool IsFamily { get; }

/// <summary>
/// Gets a value indicating whether this member is private.
/// </summary>
bool IsPrivate { get; }

/// <summary>
/// Gets a value indicating whether this member is public.
/// </summary>
bool IsPublic { get; }
}
}
5 changes: 5 additions & 0 deletions src/Reflection/assembly-proxying/ITypeInfoProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,10 @@ public interface ITypeInfoProxy
/// Gets a collection of the constructors defined by the current type.
/// </summary>
IEnumerable<IConstructorInfoProxy> DeclaredConstructors { get; }

/// <summary>
/// Gets a collection of the fields defined by the current type.
/// </summary>
IEnumerable<IFieldInfoProxy> DeclaredFields { get; }
}
}
61 changes: 61 additions & 0 deletions src/Reflection/assembly-proxying/mono/MonoFieldInfoProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/// <summary>
/// MonoFieldInfoProxy.cs
/// Andrea Tino - 2017
/// </summary>

namespace Rosetta.Reflection.Proxies
{
using System;
using System.Diagnostics;

using Mono.Cecil;

/// <summary>
/// Proxy for member incapsulating Mono.
/// </summary>
[DebuggerDisplay("Field {Name,nq}", Name = "MonoFieldInfoProxy {Name,nq} (Mono proxy)")]
public class MonoFieldInfoProxy : IFieldInfoProxy
{
private readonly FieldDefinition fieldDefinition;

/// <summary>
/// Initializes a new instance of the <see cref="MonoFieldInfoProxy"/> class.
/// </summary>
/// <param name="monoFieldDefinition"></param>
public MonoFieldInfoProxy(FieldDefinition monoFieldDefinition)
{
if (monoFieldDefinition == null)
{
throw new ArgumentNullException(nameof(monoFieldDefinition));
}

this.fieldDefinition = monoFieldDefinition;
}

/// <summary>
/// Gets the name of the parameter.
/// </summary>
public string Name => this.fieldDefinition.Name;

/// <summary>
/// Gets the Type of this field.
/// </summary>
public ITypeProxy FieldType => new MonoTypeProxy(this.fieldDefinition.FieldType);

/// <summary>
/// Gets a value indicating whether the field or constructor is visible only within its class
/// and derived classes.
/// </summary>
public bool IsFamily => this.fieldDefinition.IsFamily;

/// <summary>
/// Gets a value indicating whether this member is private.
/// </summary>
public bool IsPrivate => this.fieldDefinition.IsPrivate;

/// <summary>
/// Gets a value indicating whether this member is public.
/// </summary>
public bool IsPublic => this.fieldDefinition.IsPublic;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Rosetta.Reflection.Proxies
using Mono.Cecil;

/// <summary>
/// Proxy for Assembly incapsulating Mono.
/// Proxy for parameter info incapsulating Mono.
/// </summary>
[DebuggerDisplay("Method {Name,nq}", Name = "Method {Name,nq} (Mono proxy)")]
public class MonoParameterInfoProxy : IParameterInfoProxy
Expand Down
7 changes: 7 additions & 0 deletions src/Reflection/assembly-proxying/mono/MonoTypeInfoProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ public MonoTypeInfoProxy(TypeDefinition monoTypeDefinition)
? this.typeDefinition.Methods.Where(method => method.IsConstructor).Select(method => new MonoConstructorInfoProxy(method))
: null;

/// <summary>
/// Gets a collection of the fields defined by the current type.
/// </summary>
public IEnumerable<IFieldInfoProxy> DeclaredFields => this.typeDefinition.HasFields && this.typeDefinition.Fields.Where(field => field.IsStatic).Count() > 0
? this.typeDefinition.Fields.Where(method => method.IsStatic).Select(field => new MonoFieldInfoProxy(field))
: null;

// Used by debugger
private string MetadataType
{
Expand Down
67 changes: 67 additions & 0 deletions src/Reflection/factories/EnumDeclarationSyntaxFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/// <summary>
/// EnumDeclarationSyntaxFactory.cs
/// Andrea Tino - 2017
/// </summary>

namespace Rosetta.Reflection.Factories
{
using System;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

using Rosetta.Reflection.Helpers;
using Rosetta.Reflection.Proxies;

/// <summary>
/// Factory for generating a <see cref="EnumDeclarationSyntax"/>.
/// </summary>
public class EnumDeclarationSyntaxFactory : ISyntaxFactory
{
private readonly ITypeInfoProxy enumInfo;

/// <summary>
/// Initializes a new instance of the <see cref="EnumDeclarationSyntaxFactory"/> class.
/// </summary>
/// <param name="classInfo"></param>
public EnumDeclarationSyntaxFactory(ITypeInfoProxy enumInfo)
{
if (enumInfo == null)
{
throw new ArgumentNullException(nameof(enumInfo));
}

this.enumInfo = enumInfo;
}

/// <summary>
/// Creates the <see cref="InterfaceDeclarationSyntax"/>.
/// </summary>
/// <returns></returns>
public SyntaxNode Create()
{
var enumNode = SyntaxFactory.EnumDeclaration(this.enumInfo.Name);

// Defining accessibility
var visibility = new Visibility(this.enumInfo).Token;
if (visibility != SyntaxKind.None)
{
enumNode = enumNode.AddModifiers(SyntaxFactory.Token(visibility));
}

// Values
var values = this.enumInfo.DeclaredFields;

if (values != null)
{
foreach (var value in values)
{
enumNode = enumNode.AddMembers(SyntaxFactory.EnumMemberDeclaration(value.Name));
}
}

return enumNode;
}
}
}
56 changes: 56 additions & 0 deletions src/Reflection/factories/FieldDeclarationSyntaxFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/// <summary>
/// FieldDeclarationSyntaxFactory.cs
/// Andrea Tino - 2017
/// </summary>

namespace Rosetta.Reflection.Factories
{
using System;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

using Rosetta.Reflection.Helpers;
using Rosetta.Reflection.Proxies;

/// <summary>
/// Factory for generating a <see cref="FieldDeclarationSyntax"/>.
/// </summary>
public class FieldDeclarationSyntaxFactory : ISyntaxFactory
{
private readonly IFieldInfoProxy fieldInfo;

/// <summary>
/// Initializes a new instance of the <see cref="FieldDeclarationSyntaxFactory"/> class.
/// </summary>
/// <param name="propertyInfo"></param>
/// <param name="withBody"></param>
public FieldDeclarationSyntaxFactory(IFieldInfoProxy fieldInfo)
{
if (fieldInfo == null)
{
throw new ArgumentNullException(nameof(fieldInfo));
}

this.fieldInfo = fieldInfo;
}

/// <summary>
/// Creates the <see cref="PropertyDeclarationSyntax"/>.
/// </summary>
/// <returns></returns>
public SyntaxNode Create()
{
var varDeclaration = SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName(this.fieldInfo.FieldType.FullName),
new SeparatedSyntaxList<VariableDeclaratorSyntax>()
.Add(SyntaxFactory.VariableDeclarator(this.fieldInfo.Name)));
var fieldDeclaration = SyntaxFactory.FieldDeclaration(varDeclaration);

// Defining accessibility
fieldDeclaration = fieldDeclaration.AddModifiers(SyntaxFactory.Token(new Visibility(this.fieldInfo).Token));

return fieldDeclaration;
}
}
}
Loading

0 comments on commit f35e782

Please sign in to comment.