Skip to content

Commit

Permalink
Added support for interfaces
Browse files Browse the repository at this point in the history
Interfaces in ScriptSharp definition generation are not emitted at full!
Only the interface name and base list.

Targets #41
  • Loading branch information
andry-tino committed May 18, 2017
1 parent a41f6f9 commit 428b0c5
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 52 deletions.
11 changes: 9 additions & 2 deletions src/Reflection/ASTBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,18 @@ private MemberDeclarationSyntax BuildClassNode(ITypeInfoProxy type)

private MemberDeclarationSyntax BuildStructNode(ITypeInfoProxy type)
{
return this.BuildNode(type, SyntaxFactory.StructDeclaration);
return this.BuildNode(type, this.BuildInterfaceNodeCore(type));
}

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

private MemberDeclarationSyntax BuildInterfaceNode(ITypeInfoProxy type)
{
// TODO
return this.BuildNode(type, SyntaxFactory.InterfaceDeclaration);
}

Expand All @@ -138,7 +140,12 @@ private SemanticModel RetrieveSemanticModel(SyntaxTree tree)

private MemberDeclarationSyntax BuildClassNodeCore(ITypeInfoProxy type)
{
return new ClassDeclarationSyntaxFactory(type).Create();
return new ClassDeclarationSyntaxFactory(type).Create() as MemberDeclarationSyntax;
}

private MemberDeclarationSyntax BuildInterfaceNodeCore(ITypeInfoProxy type)
{
return new InterfaceDeclarationSyntaxFactory(type).Create() as MemberDeclarationSyntax;
}

// TODO: Remove this once all core methods have been built
Expand Down
2 changes: 2 additions & 0 deletions src/Reflection/Reflection.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@
<Compile Include="ASTInfo.cs" />
<Compile Include="factories\ClassDeclarationSyntaxFactory.cs" />
<Compile Include="factories\ConstructorDeclarationSyntaxFactory.cs" />
<Compile Include="factories\InterfaceDeclarationSyntaxFactory.cs" />
<Compile Include="factories\ISyntaxFactory.cs" />
<Compile Include="factories\MethodDeclarationSyntaxFactory.cs" />
<Compile Include="helpers\ObjectClass.cs" />
<Compile Include="helpers\Visibility.cs" />
Expand Down
22 changes: 12 additions & 10 deletions src/Reflection/factories/ClassDeclarationSyntaxFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// <summary>
/// Visibility.cs
/// ClassDeclarationSyntaxFactory.cs
/// Andrea Tino - 2017
/// </summary>

Expand All @@ -17,9 +17,9 @@ namespace Rosetta.Reflection.Factories
/// <summary>
/// Factory for generating a <see cref="ClassDeclarationSyntax"/>.
/// </summary>
public class ClassDeclarationSyntaxFactory
public class ClassDeclarationSyntaxFactory : ISyntaxFactory
{
private ITypeInfoProxy classInfo;
private readonly ITypeInfoProxy classInfo;

/// <summary>
/// Initializes a new instance of the <see cref="ClassDeclarationSyntaxFactory"/> class.
Expand All @@ -39,7 +39,7 @@ public ClassDeclarationSyntaxFactory(ITypeInfoProxy classInfo)
/// Creates the <see cref="ClassDeclarationSyntax"/>.
/// </summary>
/// <returns></returns>
public ClassDeclarationSyntax Create()
public SyntaxNode Create()
{
var classNode = SyntaxFactory.ClassDeclaration(this.classInfo.Name);

Expand All @@ -52,14 +52,13 @@ public ClassDeclarationSyntax Create()

// Base type
var baseType = this.classInfo.BaseType;

// Filter out the SYstem.Object class
if (baseType != null && !(new ObjectClass(baseType).Is))

if (baseType != null && !(new ObjectClass(baseType).Is)) // Filter out the System.Object class
{
classNode = classNode.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(baseType.FullName)));
}

// Interfaces
// Interface implementations
var interfaces = this.classInfo.ImplementedInterfaces;

if (interfaces != null)
Expand All @@ -77,7 +76,7 @@ public ClassDeclarationSyntax Create()
{
foreach (var ctor in ctors)
{
classNode = classNode.AddMembers(new ConstructorDeclarationSyntaxFactory(ctor, this.classInfo).Create());
classNode = classNode.AddMembers(new ConstructorDeclarationSyntaxFactory(ctor, this.classInfo).Create() as ConstructorDeclarationSyntax);
}
}

Expand All @@ -88,10 +87,13 @@ public ClassDeclarationSyntax Create()
{
foreach (var method in methods)
{
classNode = classNode.AddMembers(new MethodDeclarationSyntaxFactory(method).Create());
classNode = classNode.AddMembers(new MethodDeclarationSyntaxFactory(method).Create() as MethodDeclarationSyntax);
}
}

// Properties
// TODO

return classNode;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ namespace Rosetta.Reflection.Factories
/// <summary>
/// Factory for generating a <see cref="ConstructorDeclarationSyntax"/>.
/// </summary>
public class ConstructorDeclarationSyntaxFactory
public class ConstructorDeclarationSyntaxFactory : ISyntaxFactory
{
private ITypeInfoProxy classInfo;
private IConstructorInfoProxy ctorInfo;
private readonly ITypeInfoProxy classInfo;
private readonly IConstructorInfoProxy ctorInfo;

/// <summary>
/// Initializes a new instance of the <see cref="ConstructorDeclarationSyntaxFactory"/> class.
Expand All @@ -47,7 +47,7 @@ public ConstructorDeclarationSyntaxFactory(IConstructorInfoProxy ctorInfo, IType
/// Creates the <see cref="ConstructorDeclarationSyntax"/>.
/// </summary>
/// <returns></returns>
public ConstructorDeclarationSyntax Create()
public SyntaxNode Create()
{
var ctorDeclaration = SyntaxFactory.ConstructorDeclaration(this.classInfo.Name);

Expand Down
24 changes: 24 additions & 0 deletions src/Reflection/factories/ISyntaxFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// <summary>
/// ISyntaxFactory.cs
/// Andrea Tino - 2017
/// </summary>

namespace Rosetta.Reflection.Factories
{
using System;

using Microsoft.CodeAnalysis;

/// <summary>
/// Abstract common funcitonalities of syntax factories.
/// </summary>
public interface ISyntaxFactory
{

/// <summary>
/// Creates a <see cref="SyntaxNode"/>.
/// </summary>
/// <returns></returns>
SyntaxNode Create();
}
}
81 changes: 81 additions & 0 deletions src/Reflection/factories/InterfaceDeclarationSyntaxFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/// <summary>
/// InterfaceDeclarationSyntaxFactory.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="InterfaceDeclarationSyntax"/>.
/// </summary>
public class InterfaceDeclarationSyntaxFactory : ISyntaxFactory
{
private readonly ITypeInfoProxy interfaceInfo;

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

this.interfaceInfo = interfaceInfo;
}

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

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

// Extended interfaces
var interfaces = this.interfaceInfo.ImplementedInterfaces;

if (interfaces != null)
{
foreach (var @interface in interfaces)
{
interfaceNode = interfaceNode.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(@interface.FullName)));
}
}

// Methods
var methods = this.interfaceInfo.DeclaredMethods;

if (methods != null)
{
foreach (var method in methods)
{
interfaceNode = interfaceNode.AddMembers(new MethodDeclarationSyntaxFactory(method, false).Create() as MethodDeclarationSyntax);
}
}

// Properties
// TODO

return interfaceNode;
}
}
}
16 changes: 11 additions & 5 deletions src/Reflection/factories/MethodDeclarationSyntaxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,32 @@ namespace Rosetta.Reflection.Factories
/// <summary>
/// Factory for generating a <see cref="MethodDeclarationSyntax"/>.
/// </summary>
public class MethodDeclarationSyntaxFactory
public class MethodDeclarationSyntaxFactory : ISyntaxFactory
{
private IMethodInfoProxy methodInfo;
private readonly IMethodInfoProxy methodInfo;
private readonly bool withBody;

/// <summary>
/// Initializes a new instance of the <see cref="MethodDeclarationSyntaxFactory"/> class.
/// </summary>
/// <param name="methodInfo"></param>
public MethodDeclarationSyntaxFactory(IMethodInfoProxy methodInfo)
/// <param name="withBody"></param>
public MethodDeclarationSyntaxFactory(IMethodInfoProxy methodInfo, bool withBody = true)
{
if (methodInfo == null)
{
throw new ArgumentNullException(nameof(methodInfo));
}

this.methodInfo = methodInfo;
this.withBody = withBody;
}

/// <summary>
/// Creates the <see cref="MethodDeclarationSyntax"/>.
/// </summary>
/// <returns></returns>
public MethodDeclarationSyntax Create()
public SyntaxNode Create()
{
var methodDeclaration = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName(this.methodInfo.ReturnType.FullName), this.methodInfo.Name);

Expand All @@ -59,7 +62,10 @@ public MethodDeclarationSyntax Create()
}

// Dummy body
methodDeclaration = methodDeclaration.WithBody(DummyBody.GenerateForMerhod());
if (this.withBody)
{
methodDeclaration = methodDeclaration.WithBody(DummyBody.GenerateForMerhod());
}

return methodDeclaration;
}
Expand Down
1 change: 1 addition & 0 deletions test/Reflection.UnitTests/Reflection.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
<Compile Include="Class.cs" />
<Compile Include="factories\ClassDeclarationSyntaxFactoryTest.cs" />
<Compile Include="factories\ConstructorDeclarationSyntaxFactoryTest.cs" />
<Compile Include="factories\InterfaceDeclarationSyntaxFactoryTest.cs" />
<Compile Include="factories\MethodDeclarationSyntaxFactoryTest.cs" />
<Compile Include="helpers\ObjectClassTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ class MyClass {
Assert.IsNotNull(syntaxNode, "A node was expected to be built");
Assert.IsInstanceOfType(syntaxNode, typeof(ClassDeclarationSyntax), "Expected a class declaration node to be built");

var name = syntaxNode.Identifier.Text;
var classDeclarationSyntaxNode = syntaxNode as ClassDeclarationSyntax;

var name = classDeclarationSyntaxNode.Identifier.Text;
Assert.AreEqual("MyClass", name, "Class name not correctly acquired");
}

Expand Down Expand Up @@ -74,7 +76,9 @@ class MyClass {
Assert.IsNotNull(syntaxNode, "A node was expected to be built");
Assert.IsInstanceOfType(syntaxNode, typeof(ClassDeclarationSyntax), "Expected a class declaration node to be built");

var baseList = syntaxNode.BaseList;
var classDeclarationSyntaxNode = syntaxNode as ClassDeclarationSyntax;

var baseList = classDeclarationSyntaxNode.BaseList;
Assert.IsNull(baseList, "No base class should have been generated");
}

Expand All @@ -87,18 +91,22 @@ namespace MyNamespace {
public class MyClass {
}
}
", SyntaxKind.PublicKeyword);
", "MyClass", SyntaxKind.PublicKeyword);

// Implicitely internal
TestVisibility(@"
namespace MyNamespace {
class MyClass {
}
}
", null);
", "MyClass", null);
}

private static void TestVisibility(string source, SyntaxKind? expectedVisibility)
// TODO: Missing test for base class

// TODO: Missing test for implemented interfaces

private static void TestVisibility(string source, string className, SyntaxKind? expectedVisibility)
{
// Assembling some code
IAssemblyLoader assemblyLoader = new Utils.AsmlDasmlAssemblyLoader(source);
Expand All @@ -107,7 +115,7 @@ private static void TestVisibility(string source, SyntaxKind? expectedVisibility
IAssemblyProxy assembly = assemblyLoader.Load();

// Locating the class
ITypeInfoProxy classDefinition = assembly.LocateType("MyClass");
ITypeInfoProxy classDefinition = assembly.LocateType(className);

Assert.IsNotNull(classDefinition);

Expand All @@ -118,7 +126,9 @@ private static void TestVisibility(string source, SyntaxKind? expectedVisibility
Assert.IsNotNull(syntaxNode, "A node was expected to be built");
Assert.IsInstanceOfType(syntaxNode, typeof(ClassDeclarationSyntax), "Expected a class declaration node to be built");

var modifiers = syntaxNode.Modifiers;
var classDeclarationSyntaxNode = syntaxNode as ClassDeclarationSyntax;

var modifiers = classDeclarationSyntaxNode.Modifiers;

if (expectedVisibility.HasValue)
{
Expand Down
Loading

0 comments on commit 428b0c5

Please sign in to comment.