diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/AbstractClassProxyGeneratorTests.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/AbstractClassProxyGeneratorTests.cs new file mode 100644 index 0000000000..4952905317 --- /dev/null +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/AbstractClassProxyGeneratorTests.cs @@ -0,0 +1,188 @@ +using Amazon.JSII.Generator.Class; +using Amazon.JSII.JsonModel.Spec; +using Xunit; + +namespace Amazon.JSII.Generator.UnitTests.Class +{ + public class AbstractClassProxyGeneratorTests : GeneratorTestBase + { + private const string Prefix = nameof(Generator) + "." + nameof(AbstractClassProxyGenerator) + "."; + + private string Render(ClassType classType) + { + Symbols.MapTypeToPackage("myFqn", classType.Assembly); + Symbols.MapNamespace(classType.QualifiedNamespace, "MyNamespace"); + Symbols.MapTypeName("myFqn", "MyClass", TypeKind.Class); + + var generator = new AbstractClassProxyGenerator(classType.Assembly, classType, Symbols, Namespaces); + + var syntaxTree = generator.CreateSyntaxTree(); + return syntaxTree.ToString(); + } + + [Fact(DisplayName = Prefix + nameof(IncludesAttribute))] + public void IncludesAttribute() + { + var classType = new ClassType + ( + "myFqn", + "myPackage", + "myClass", + true, + initializer: new Method(true, false, false) + ); + + var actual = Render(classType); + var expected = + @"namespace MyNamespace +{ + [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")] + internal class MyClassProxy : MyClass + { + private MyClassProxy(ByRefValue reference): base(reference) + { + } + } +}"; + Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); + } + + [Fact(DisplayName = Prefix + nameof(IncludesDocs))] + public void IncludesDocs() + { + // Docs are not currently generated as part of the C# code. + ClassType classType = new ClassType + ( + fullyQualifiedName: "myFqn", + assembly: "myPackage", + name: "myClass", + isAbstract: true, + initializer: new Method(true, false, false), + docs: new Docs {{"foo", "bar"}} + ); + + string actual = Render(classType); + string expected = + @"namespace MyNamespace +{ + /// foo: bar + [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")] + internal class MyClassProxy : MyClass + { + private MyClassProxy(ByRefValue reference): base(reference) + { + } + } +}"; + Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); + } + + [Fact(DisplayName = Prefix + nameof(IncludesProperties))] + public void IncludesProperties() + { + ClassType classType = new ClassType + ( + fullyQualifiedName: "myFqn", + assembly: "myPackage", + name: "myClass", + isAbstract: true, + initializer: new Method(true, false, false), + properties: new[] + { + new Property + ( + name: "myProp", + type: new TypeReference("myPropTypeFqn"), + isImmutable: false, + isAbstract: true, + isProtected: false + ), + new Property + ( + name: "notMyProp", + type: new TypeReference("myPropTypeFqn"), + isImmutable: false, + isAbstract: false, + isProtected: false + ) + } + ); + + Symbols.MapTypeName("myPropTypeFqn", "MyPropType", TypeKind.Class); + Symbols.MapPropertyName("myFqn", "myProp", "MyProp"); + + string actual = Render(classType); + string expected = + @"namespace MyNamespace +{ + [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")] + internal class MyClassProxy : MyClass + { + private MyClassProxy(ByRefValue reference): base(reference) + { + } + + [JsiiProperty(""myProp"", ""{\""fqn\"":\""myPropTypeFqn\""}"")] + public override MyPropType MyProp + { + get => GetInstanceProperty(); + set => SetInstanceProperty(value); + } + } +}"; + Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); + } + + [Fact(DisplayName = Prefix + nameof(IncludesMethods))] + public void IncludesMethods() + { + ClassType classType = new ClassType + ( + fullyQualifiedName: "myFqn", + assembly: "myPackage", + name: "myClass", + isAbstract: true, + initializer: new Method(true, false, false), + methods: new[] + { + new Method + ( + false, + false, + true, + name: "myMethod" + ), + new Method + ( + false, + false, + false, + name: "notMyMethod" + ) + } + ); + + Symbols.MapMethodName("myFqn", "myMethod", "MyMethod"); + + string actual = Render(classType); + string expected = + @"namespace MyNamespace +{ + [JsiiInterfaceProxy(typeof(MyClass), ""myFqn"")] + internal class MyClassProxy : MyClass + { + private MyClassProxy(ByRefValue reference): base(reference) + { + } + + [JsiiMethod(""myMethod"", null, ""[]"")] + public override void MyMethod() + { + InvokeInstanceVoidMethod(new object[]{}); + } + } +}"; + Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs index 7c463047aa..f430a9b358 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/Class/ClassGeneratorTests.cs @@ -1,20 +1,20 @@ using Amazon.JSII.Generator.Class; -using Amazon.JSII.Generator.Interface; using Amazon.JSII.JsonModel.Spec; using Microsoft.CodeAnalysis; using Xunit; +using TypeKind = Amazon.JSII.JsonModel.Spec.TypeKind; namespace Amazon.JSII.Generator.UnitTests.Class { public class ClassGeneratorTests : GeneratorTestBase { - const string Prefix = nameof(Generator) + "." + nameof(InterfaceGenerator) + "."; + const string Prefix = nameof(Generator) + "." + nameof(ClassGenerator) + "."; - string Render(ClassType classType) + private string Render(ClassType classType) { Symbols.MapTypeToPackage("myFqn", classType.Assembly); Symbols.MapNamespace(classType.QualifiedNamespace, "MyNamespace"); - Symbols.MapTypeName("myFqn", "MyClass", JsonModel.Spec.TypeKind.Class); + Symbols.MapTypeName("myFqn", "MyClass", TypeKind.Class); ClassGenerator generator = new ClassGenerator(classType.Assembly, classType, Symbols, Namespaces); @@ -36,7 +36,7 @@ public void IncludesAttribute() string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] public class MyClass : DeputyBase @@ -71,7 +71,7 @@ public void IncludesAbstractKeyword() string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] public abstract class MyClass : DeputyBase @@ -103,12 +103,12 @@ public void IncludesDocs() name: "myClass", isAbstract: false, initializer: new Method(true, false, false), - docs: new Docs { { "foo", "bar" } } + docs: new Docs {{"foo", "bar"}} ); string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { /// foo: bar [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] @@ -144,7 +144,7 @@ public void IncludesProperties() { new Property ( - name: "myProp", + name: "myProp", type: new TypeReference("myPropTypeFqn"), isImmutable: false, isAbstract: false, @@ -153,12 +153,12 @@ public void IncludesProperties() } ); - Symbols.MapTypeName("myPropTypeFqn", "MyPropType", JsonModel.Spec.TypeKind.Class); + Symbols.MapTypeName("myPropTypeFqn", "MyPropType", TypeKind.Class); Symbols.MapPropertyName("myFqn", "myProp", "MyProp"); string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] public class MyClass : DeputyBase @@ -212,7 +212,7 @@ public void IncludesMethods() string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] public class MyClass : DeputyBase @@ -252,11 +252,11 @@ public void IncludesBase() @base: new TypeReference("myBaseTypeFqn") ); - Symbols.MapTypeName("myBaseTypeFqn", "MyBaseType", JsonModel.Spec.TypeKind.Class); + Symbols.MapTypeName("myBaseTypeFqn", "MyBaseType", TypeKind.Class); string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] public class MyClass : MyBaseType @@ -294,12 +294,12 @@ public void IncludesInterfaces() } ); - Symbols.MapTypeName("myInterfaceFqn1", "MyInterface1", JsonModel.Spec.TypeKind.Interface); - Symbols.MapTypeName("myInterfaceFqn2", "MyInterface2", JsonModel.Spec.TypeKind.Interface); + Symbols.MapTypeName("myInterfaceFqn1", "MyInterface1", TypeKind.Interface); + Symbols.MapTypeName("myInterfaceFqn2", "MyInterface2", TypeKind.Interface); string actual = Render(classType); string expected = -@"namespace MyNamespace + @"namespace MyNamespace { [JsiiClass(typeof(MyClass), ""myFqn"", ""[]"")] public class MyClass : DeputyBase, IMyInterface1, IMyInterface2 @@ -320,4 +320,4 @@ protected MyClass(DeputyProps props): base(props) Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); } } -} +} \ No newline at end of file diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs index 4d2bd4cb2d..ed6093e7fa 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator.UnitTests/SymbolMapExtensions.cs @@ -1,7 +1,6 @@ using Amazon.JSII.JsonModel.Spec; using NSubstitute; using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -using Type = Amazon.JSII.JsonModel.Spec.Type; namespace Amazon.JSII.Generator.UnitTests { @@ -91,6 +90,15 @@ public static void MapTypeName(this ISymbolMap symbols, string fullyQualifiedNam frameworkName = $"I{frameworkName}"; } + if (kind == TypeKind.Class) + { + string proxyName = $"{frameworkName}Proxy"; + + symbols + .GetAbstractClassProxyName(Arg.Is(t => t.FullyQualifiedName == fullyQualifiedName), disambiguate: Arg.Any()) + .Returns(proxyName); + } + symbols .GetName(Arg.Is(t => t.FullyQualifiedName == fullyQualifiedName), disambiguate: Arg.Any()) .Returns(frameworkName); diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs index d05786067c..6e087b8d45 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/AssemblyGenerator.cs @@ -281,25 +281,47 @@ void SaveType(Type type) switch (type.Kind) { case TypeKind.Class: - SaveTypeFile($"{symbols.GetName(type)}.cs", new ClassGenerator(assembly.Name, (ClassType)type, symbols).CreateSyntaxTree()); + { + var classType = (ClassType) type; + + if (classType.IsAbstract) + { + SaveTypeFile($"{symbols.GetAbstractClassProxyName(classType)}.cs", + new AbstractClassProxyGenerator(assembly.Name, classType, symbols).CreateSyntaxTree()); + } + + SaveTypeFile($"{symbols.GetName(type)}.cs", + new ClassGenerator(assembly.Name, classType, symbols).CreateSyntaxTree()); return; + } case TypeKind.Enum: - SaveTypeFile($"{symbols.GetName(type)}.cs", new EnumGenerator(assembly.Name, (EnumType)type, symbols).CreateSyntaxTree()); + { + SaveTypeFile($"{symbols.GetName(type)}.cs", + new EnumGenerator(assembly.Name, (EnumType) type, symbols).CreateSyntaxTree()); return; + } case TypeKind.Interface: - InterfaceType interfaceType = (InterfaceType)type; + { + InterfaceType interfaceType = (InterfaceType) type; - SaveTypeFile($"{symbols.GetName(interfaceType)}.cs", new InterfaceGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree()); - SaveTypeFile($"{symbols.GetInterfaceProxyName(interfaceType)}.cs", new InterfaceProxyGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree()); + SaveTypeFile($"{symbols.GetName(interfaceType)}.cs", + new InterfaceGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree()); + SaveTypeFile($"{symbols.GetInterfaceProxyName(interfaceType)}.cs", + new InterfaceProxyGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree()); if (interfaceType.IsDataType == true) { - SaveTypeFile($"{symbols.GetInterfaceDefaultName(interfaceType)}.cs", new InterfaceDefaultGenerator(assembly.Name, interfaceType, symbols).CreateSyntaxTree()); + SaveTypeFile($"{symbols.GetInterfaceDefaultName(interfaceType)}.cs", + new InterfaceDefaultGenerator(assembly.Name, interfaceType, symbols) + .CreateSyntaxTree()); } return; + } default: + { throw new ArgumentException($"Unkown type kind: {type.Kind}", nameof(type)); + } } void SaveTypeFile(string filename, SyntaxTree syntaxTree) diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyGenerator.cs new file mode 100644 index 0000000000..d4549f2fad --- /dev/null +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyGenerator.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Amazon.JSII.JsonModel.Spec; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using Type = Amazon.JSII.JsonModel.Spec.Type; + +namespace Amazon.JSII.Generator.Class +{ + public class AbstractClassProxyGenerator : TypeProxyGeneratorBase + { + public AbstractClassProxyGenerator(string package, ClassType type, ISymbolMap symbols, + INamespaceSet namespaces = null) + : base(package, type, symbols, namespaces) + { + if (!type.IsAbstract) + { + throw new ArgumentException("Class type must be abstract.", nameof(type)); + } + } + + protected override SyntaxToken GetProxyTypeNameSyntax() + { + return SF.Identifier(Symbols.GetAbstractClassProxyName(Type)); + } + + protected override IEnumerable CreateProperties() + { + foreach (Property property in GetAllProperties(Type)) + { + var generator = new AbstractClassProxyPropertyGenerator(Type, property, Symbols, Namespaces); + yield return generator.CreateProperty(); + } + } + + protected override IEnumerable CreateMethods() + { + foreach (Method method in GetAllMethods(Type)) + { + var generator = new AbstractClassProxyMethodGenerator(Type, method, Symbols, Namespaces); + yield return generator.CreateMethod(); + } + } + + private IEnumerable GetAllMethods(Type type) + { + IEnumerable GetAllMethodsRecurse(Type currentType, IEnumerable methods) + { + if (currentType is InterfaceType interfaceType) + { + methods = methods.Concat(interfaceType.Methods ?? new Method[0]); + + if (interfaceType.Interfaces != null) + { + var superinterfaceMethods = interfaceType.Interfaces.Select(r => + Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as + InterfaceType) + .SelectMany(i => GetAllMethodsRecurse(i, methods)) + .ToList(); + + methods = methods.Concat(superinterfaceMethods); + } + } + else if (currentType is ClassType classType) + { + methods = methods.Concat(classType.Methods ?? new Method[0]); + + if (classType.Interfaces != null) + { + var superinterfaceMethods = classType.Interfaces.Select(r => + Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as + InterfaceType) + .SelectMany(i => GetAllMethodsRecurse(i, methods)) + .ToList(); + + methods = methods.Concat(superinterfaceMethods); + } + + if (classType.Base != null) + { + methods = methods.Concat(GetAllMethodsRecurse( + Symbols.GetTypeFromFullyQualifiedName(classType.Base.FullyQualifiedName) as ClassType, + methods)); + } + } + + return methods; + } + + return GetAllMethodsRecurse(type, new List()) + .GroupBy(m => (m.Name, + string.Join("", + m.Parameters?.Select(p => p.Name + p.Type.FullyQualifiedName) ?? Enumerable.Empty()))) + .Select(g => g.First()) + .Where(m => m.IsAbstract ?? false); + } + + private IEnumerable GetAllProperties(Type type) + { + IEnumerable GetAllPropertiesRecurse(Type currentType, IEnumerable properties) + { + if (currentType is InterfaceType interfaceType) + { + properties = properties.Concat(interfaceType.Properties ?? new Property[0]); + + if (interfaceType.Interfaces != null) + { + var superinterfaceMethods = interfaceType.Interfaces.Select(r => + Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as + InterfaceType) + .SelectMany(i => GetAllPropertiesRecurse(i, properties)) + .ToList(); + + properties = properties.Concat(superinterfaceMethods); + } + } + else if (currentType is ClassType classType) + { + properties = + properties.Concat(classType.Properties ?? new Property[0]); + + if (classType.Interfaces != null) + { + var superinterfaceMethods = classType.Interfaces.Select(r => + Symbols.GetTypeFromFullyQualifiedName(r.FullyQualifiedName) as + InterfaceType) + .SelectMany(i => GetAllPropertiesRecurse(i, properties)) + .ToList(); + + properties = properties.Concat(superinterfaceMethods); + } + + if (classType.Base != null) + { + properties = properties.Concat(GetAllPropertiesRecurse( + Symbols.GetTypeFromFullyQualifiedName(classType.Base.FullyQualifiedName) as ClassType, + properties)); + } + } + + return properties; + } + + return GetAllPropertiesRecurse(type, new List()) + .GroupBy(p => p.Name) + .Select(g => g.First()) + .Where(p => p.IsAbstract ?? false); + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyMethodGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyMethodGenerator.cs new file mode 100644 index 0000000000..f1114309b7 --- /dev/null +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyMethodGenerator.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Amazon.JSII.JsonModel.Spec; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Amazon.JSII.Generator.Class +{ + public class AbstractClassProxyMethodGenerator : ClassMethodGenerator + { + public AbstractClassProxyMethodGenerator(ClassType type, Method method, ISymbolMap symbols, + INamespaceSet namespaces) : base(type, method, symbols, namespaces) + { + } + + protected override IEnumerable GetModifierKeywords() + { + yield return Method.IsProtected ? SyntaxKind.ProtectedKeyword : SyntaxKind.PublicKeyword; + // Abstract class proxies can only contain overwritten members. + yield return SyntaxKind.OverrideKeyword; + } + + protected override BlockSyntax GetBody() + { + if (Method.Returns == null) + { + return SF.Block(SF.ExpressionStatement(CreateInvocationExpression())); + } + + return SF.Block(SF.ReturnStatement(CreateInvocationExpression())); + } + + protected override bool HasSemicolon => false; + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyPropertyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyPropertyGenerator.cs new file mode 100644 index 0000000000..13be50b533 --- /dev/null +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/AbstractClassProxyPropertyGenerator.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Amazon.JSII.JsonModel.Spec; +using Microsoft.CodeAnalysis.CSharp; + +namespace Amazon.JSII.Generator.Class +{ + public class AbstractClassProxyPropertyGenerator : ClassPropertyGenerator + { + public AbstractClassProxyPropertyGenerator(ClassType type, Property property, ISymbolMap symbols, + INamespaceSet namespaces) : base(type, property, symbols, namespaces) + { + } + + protected override IEnumerable GetModifierKeywords() + { + yield return Property.IsProtected == true ? SyntaxKind.ProtectedKeyword : SyntaxKind.PublicKeyword; + // Abstract class proxies can only contain overwritten members. + yield return SyntaxKind.OverrideKeyword; + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs index 8108c3d091..074bdf3abb 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Class/ClassMethodGenerator.cs @@ -1,10 +1,8 @@ -using Amazon.JSII.JsonModel.Spec; -using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; +using Amazon.JSII.JsonModel.Spec; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Linq; using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Amazon.JSII.Generator.Class @@ -16,15 +14,15 @@ public ClassMethodGenerator(ClassType type, Method method, ISymbolMap symbols, I { } - bool IsDefinedOnAncestor + private bool IsDefinedOnAncestor { get { - string[] objectMethods = new[] + string[] objectMethods = { "ToString", "GetHashCode", - "Equals", + "Equals" }; if (objectMethods.Contains(NameUtils.ConvertMethodName(Method.Name))) @@ -79,4 +77,4 @@ protected override BlockSyntax GetBody() protected override bool HasSemicolon => Method.IsAbstract == true; } -} +} \ No newline at end of file diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs index d60230587f..030170385a 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/ISymbolMap.cs @@ -15,6 +15,8 @@ public interface ISymbolMap string GetName(Type type, bool disambiguate = false); string GetName(string fullyQualifiedName, bool disambiguate = false); + + string GetAbstractClassProxyName(ClassType type, bool disambiguate = false); string GetInterfaceProxyName(InterfaceType type, bool disambiguate = false); diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs index 9935708ce0..d4b806f0cf 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/Interface/InterfaceProxyGenerator.cs @@ -1,98 +1,24 @@ -using Amazon.JSII.JsonModel.Spec; +using System.Collections.Generic; +using Amazon.JSII.JsonModel.Spec; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Linq; using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Amazon.JSII.Generator.Interface { - public class InterfaceProxyGenerator : TypeGeneratorBase + public class InterfaceProxyGenerator : TypeProxyGeneratorBase { public InterfaceProxyGenerator(string package, InterfaceType type, ISymbolMap symbols, INamespaceSet namespaces = null) : base(package, type, symbols, namespaces) { } - - protected override MemberDeclarationSyntax CreateType() - { - return SF.ClassDeclaration - ( - CreateAttributes(), - SF.TokenList(SF.Token(SyntaxKind.InternalKeyword)), - GetProxyTypeNameSyntax(), - null, - CreateBaseList(), - SF.List(), - SF.List(CreateMembers()) - ); - - SyntaxList CreateAttributes() - { - TypeOfExpressionSyntax typeOfExpression = SF.TypeOfExpression(Symbols.GetNameSyntax(Type)); - SyntaxToken fullyQualifiedNameLiteral = SF.Literal(Type.FullyQualifiedName); - - return SF.List(new[] { - SF.AttributeList(SF.SeparatedList(new[] { - SF.Attribute( - SF.ParseName("JsiiInterfaceProxy"), - SF.ParseAttributeArgumentList($"({typeOfExpression}, {fullyQualifiedNameLiteral})") - ) - })) - }); - } - - BaseListSyntax CreateBaseList() - { - return SF.BaseList(SF.SeparatedList(GetBaseTypes())); - - IEnumerable GetBaseTypes() - { - yield return SF.SimpleBaseType(SF.ParseTypeName("DeputyBase")); - - Namespaces.Add(Type); - yield return SF.SimpleBaseType(Symbols.GetNameSyntax(Type, disambiguate: true)); - } - } - - IEnumerable CreateMembers() - { - return CreateConstructors() - .Concat(CreateProperties()) - .Concat(CreateMethods()); - } - } - - SyntaxToken GetProxyTypeNameSyntax() + + protected override SyntaxToken GetProxyTypeNameSyntax() { return SF.Identifier(Symbols.GetInterfaceProxyName(Type)); } - IEnumerable CreateConstructors() - { - yield return SF.ConstructorDeclaration - ( - SF.List(), - - // Only Amazon.JSII.Runtime should create interface proxies, - // so we make the constructor private. - SF.TokenList(SF.Token(SyntaxKind.PrivateKeyword)), - - GetProxyTypeNameSyntax(), - SF.ParseParameterList("(ByRefValue reference)"), - SF.ConstructorInitializer - ( - SyntaxKind.BaseConstructorInitializer, - SF.ParseArgumentList("(reference)") - ), - SF.Block(), - null - ); - } - - IEnumerable CreateProperties() + protected override IEnumerable CreateProperties() { foreach (Property property in Type.GetAllProperties(Symbols)) { @@ -101,7 +27,7 @@ IEnumerable CreateProperties() } } - IEnumerable CreateMethods() + protected override IEnumerable CreateMethods() { foreach (Method method in Type.GetAllMethods(Symbols)) { diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs index f00914887b..eb5a9a3175 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/SymbolMap.cs @@ -54,16 +54,26 @@ TypeMetadata GetMetadata(Type type) switch (type.Kind) { case JsonModel.Spec.TypeKind.Class: + { + var classType = (ClassType) type; + if (classType.IsAbstract) + { + return new AbstractClassTypeMetadata(classType, assembly); + } return new ClassTypeMetadata((ClassType)type, assembly); - + } case JsonModel.Spec.TypeKind.Enum: - return new EnumTypeMetadata((EnumType)type, assembly); - + { + return new EnumTypeMetadata((EnumType)type, assembly); + } case JsonModel.Spec.TypeKind.Interface: - return new InterfaceTypeMetadata((InterfaceType)type, assembly); - + { + return new InterfaceTypeMetadata((InterfaceType)type, assembly); + } default: - throw new ArgumentException($"Type {type.Name} has unrecognized kind {type.Kind}", nameof(type)); + { + throw new ArgumentException($"Type {type.Name} has unrecognized kind {type.Kind}", nameof(type)); + } } } } @@ -101,6 +111,18 @@ public string GetName(string fullyQualifiedName, bool disambiguate = false) return GetName(GetTypeFromFullyQualifiedName(fullyQualifiedName), disambiguate); } + public string GetAbstractClassProxyName(ClassType type, bool disambiguate = false) + { + type = type ?? throw new ArgumentNullException(nameof(type)); + + if (_types[type.FullyQualifiedName] is AbstractClassTypeMetadata metadata) + { + return metadata.ProxyName; + } + + throw new ArgumentException($"Cannot get proxy name for '{type.FullyQualifiedName}' because it is not an abstract class."); + } + public string GetInterfaceProxyName(InterfaceType type, bool disambiguate = false) { type = type ?? throw new ArgumentNullException(nameof(type)); @@ -110,7 +132,7 @@ public string GetInterfaceProxyName(InterfaceType type, bool disambiguate = fals return metadata.ProxyName; } - throw new ArgumentException($"Cannot get proxy name for '{type.FullyQualifiedName}' because it is not an interface"); + throw new ArgumentException($"Cannot get proxy name for '{type.FullyQualifiedName}' because it is not an interface."); } public string GetInterfaceDefaultName(InterfaceType type, bool disambiguate = false) @@ -122,7 +144,7 @@ public string GetInterfaceDefaultName(InterfaceType type, bool disambiguate = fa return metadata.DefaultName; } - throw new ArgumentException($"Cannot get default name for '{type.FullyQualifiedName}' because it is not an interface"); + throw new ArgumentException($"Cannot get default name for '{type.FullyQualifiedName}' because it is not an interface."); } public string GetName(Type type, Method method) diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs index 462930882e..f6f7af256b 100644 --- a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeMetadata.cs @@ -67,6 +67,31 @@ public ClassTypeMetadata(ClassType type, Assembly assembly) } } + public class AbstractClassTypeMetadata : ClassTypeMetadata + { + public string ProxyName { get; private set; } + + public string FrameworkFullyQualifiedProxyName => $"{Namespace}.{ProxyName}"; + + public AbstractClassTypeMetadata(ClassType type, Assembly assembly) + : base(type, assembly) + { + ProxyName = $"{Name}Proxy"; + } + + public override void ResolveTypeNameConflicts(ISet namespaceNames) + { + base.ResolveTypeNameConflicts(namespaceNames); + + ISet memberNames = new HashSet(MemberNames.Values); + + while (memberNames.Contains(ProxyName) || namespaceNames.Contains(FrameworkFullyQualifiedProxyName)) + { + ProxyName += "_"; + } + } + } + public class EnumTypeMetadata : TypeMetadata { public EnumTypeMetadata(EnumType type, Assembly assembly) @@ -82,7 +107,6 @@ public EnumTypeMetadata(EnumType type, Assembly assembly) MemberNames = new ReadOnlyDictionary(memberNames); Name = NameUtils.ConvertTypeName(type.Name); } - } public class InterfaceTypeMetadata : TypeMetadata diff --git a/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeProxyGeneratorBase.cs b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeProxyGeneratorBase.cs new file mode 100644 index 0000000000..5060c8f6f7 --- /dev/null +++ b/packages/jsii-dotnet-generator/src/Amazon.JSII.Generator/TypeProxyGeneratorBase.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Linq; +using Amazon.JSII.JsonModel.Spec; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Amazon.JSII.Generator +{ + public abstract class TypeProxyGeneratorBase : TypeGeneratorBase where T : Type + { + protected TypeProxyGeneratorBase(string package, T type, ISymbolMap symbols, INamespaceSet namespaces) + : base(package, type, symbols, namespaces) + { + } + + protected override MemberDeclarationSyntax CreateType() + { + return SF.ClassDeclaration + ( + CreateAttributes(), + SF.TokenList(SF.Token(SyntaxKind.InternalKeyword)), + GetProxyTypeNameSyntax(), + null, + CreateBaseList(), + SF.List(), + SF.List(CreateMembers()) + ); + + SyntaxList CreateAttributes() + { + var typeOfExpression = SF.TypeOfExpression(Symbols.GetNameSyntax(Type)); + var fullyQualifiedNameLiteral = SF.Literal(Type.FullyQualifiedName); + + return SF.List(new[] + { + SF.AttributeList(SF.SeparatedList(new[] + { + SF.Attribute( + SF.ParseName("JsiiInterfaceProxy"), + SF.ParseAttributeArgumentList($"({typeOfExpression}, {fullyQualifiedNameLiteral})") + ) + })) + }); + } + + BaseListSyntax CreateBaseList() + { + return SF.BaseList(SF.SeparatedList(GetBaseTypes())); + + IEnumerable GetBaseTypes() + { + if (IsImplementingInterface) + { + yield return SF.SimpleBaseType(SF.ParseTypeName("DeputyBase")); + } + + Namespaces.Add(Type); + yield return SF.SimpleBaseType(Symbols.GetNameSyntax(Type, disambiguate: true)); + } + } + + IEnumerable CreateMembers() + { + return CreateConstructors() + .Concat(CreateProperties()) + .Concat(CreateMethods()); + } + } + + protected virtual IEnumerable CreateConstructors() + { + yield return SF.ConstructorDeclaration + ( + SF.List(), + + // Only Amazon.JSII.Runtime should create interface proxies, + // so we make the constructor private. + SF.TokenList(SF.Token(SyntaxKind.PrivateKeyword)), + GetProxyTypeNameSyntax(), + SF.ParseParameterList("(ByRefValue reference)"), + SF.ConstructorInitializer + ( + SyntaxKind.BaseConstructorInitializer, + SF.ParseArgumentList("(reference)") + ), + SF.Block(), + null + ); + } + + private bool IsImplementingInterface => Type is InterfaceType; + + protected abstract SyntaxToken GetProxyTypeNameSyntax(); + + protected abstract IEnumerable CreateProperties(); + + protected abstract IEnumerable CreateMethods(); + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs index 58a14fc5dd..af5e834506 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/ValueConverter.cs @@ -115,7 +115,7 @@ bool IsReferenceType() return _types.GetClassType(fullyQualifiedName) != null || _types.GetInterfaceType(fullyQualifiedName) != null || - _types.GetInterfaceProxyType(fullyQualifiedName) != null; + _types.GetProxyType(fullyQualifiedName) != null; } } diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs index 3d6d3cfbf9..b5c86bb9b1 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ITypeCache.cs @@ -10,7 +10,7 @@ public interface ITypeCache Type GetInterfaceType(string fullyQualifiedName); - Type GetInterfaceProxyType(string fullyQualifiedName); + Type GetProxyType(string fullyQualifiedName); Type GetFrameworkType(JsonModel.Spec.TypeReference reference); } diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs index 0b8c171906..2e0ff6cdd5 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/ReferenceMap.cs @@ -1,8 +1,8 @@ -using Amazon.JSII.JsonModel.Api; -using Amazon.JSII.Runtime.Deputy; -using System; +using System; using System.Collections.Generic; using System.Reflection; +using Amazon.JSII.JsonModel.Api; +using Amazon.JSII.Runtime.Deputy; namespace Amazon.JSII.Runtime.Services { @@ -20,7 +20,9 @@ public void AddNativeReference(ByRefValue reference, DeputyBase nativeReference) { if (_references.ContainsKey(reference.Value)) { - throw new ArgumentException($"Cannot add reference for {reference.Value}: A reference with this name already exists", nameof(reference)); + throw new ArgumentException( + $"Cannot add reference for {reference.Value}: A reference with this name already exists", + nameof(reference)); } _references[reference.Value] = nativeReference; @@ -36,7 +38,7 @@ public DeputyBase GetOrCreateNativeReference(ByRefValue byRefValue) if (!_references.ContainsKey(byRefValue.Value)) { ConstructorInfo constructorInfo = GetByRefConstructor(); - _references[byRefValue.Value] = (DeputyBase)constructorInfo.Invoke(new object[] { byRefValue }); + _references[byRefValue.Value] = (DeputyBase) constructorInfo.Invoke(new object[] {byRefValue}); } return _references[byRefValue.Value]; @@ -46,8 +48,9 @@ ConstructorInfo GetByRefConstructor() Type type = _types.GetClassType(byRefValue.FullyQualifiedName); if (type == null) { - type = _types.GetInterfaceProxyType(byRefValue.FullyQualifiedName); + type = _types.GetProxyType(byRefValue.FullyQualifiedName); } + if (type == null) { throw new ArgumentException( @@ -58,8 +61,14 @@ ConstructorInfo GetByRefConstructor() BindingFlags constructorFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - return type.GetConstructor(constructorFlags, null, new[] { typeof(ByRefValue) }, null); + // Get proxy class implementation for abstract types. + if (type.IsClass && type.IsAbstract) + { + type = _types.GetProxyType(byRefValue.FullyQualifiedName); + } + + return type.GetConstructor(constructorFlags, null, new[] {typeof(ByRefValue)}, null); } } } -} +} \ No newline at end of file diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs index b0a5fac060..c3f5af4a3e 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/TypeCache.cs @@ -1,11 +1,13 @@ -using Microsoft.Extensions.Logging; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using PrimitiveType = Amazon.JSII.JsonModel.Spec.PrimitiveType; -using CollectionKind = Amazon.JSII.JsonModel.Spec.CollectionKind; +using Amazon.JSII.JsonModel.Spec; using Amazon.JSII.Runtime.Deputy; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Assembly = System.Reflection.Assembly; +using Type = System.Type; namespace Amazon.JSII.Runtime.Services { @@ -42,12 +44,12 @@ public Type GetInterfaceType(string fullyQualifiedName) return GetType(fullyQualifiedName); } - public Type GetInterfaceProxyType(string fullyQualifiedName) + public Type GetProxyType(string fullyQualifiedName) { return GetType(fullyQualifiedName + ProxySuffix); } - public Type GetFrameworkType(JsonModel.Spec.TypeReference reference) + public Type GetFrameworkType(TypeReference reference) { bool isOptional = reference.IsOptional == true; @@ -79,7 +81,7 @@ public Type GetFrameworkType(JsonModel.Spec.TypeReference reference) case PrimitiveType.Date: return MakeNullableIfOptional(typeof(DateTime)); case PrimitiveType.Json: - return typeof(Newtonsoft.Json.Linq.JObject); + return typeof(JObject); case PrimitiveType.Number: return MakeNullableIfOptional(typeof(double)); case PrimitiveType.String: diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon/JSII/Tests/CalculatorNamespace/BaseNamespace/BaseProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon/JSII/Tests/CalculatorNamespace/BaseNamespace/BaseProxy.cs new file mode 100644 index 0000000000..c6a14e4a18 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon/JSII/Tests/CalculatorNamespace/BaseNamespace/BaseProxy.cs @@ -0,0 +1,13 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace.BaseNamespace +{ + /// A base class. + [JsiiInterfaceProxy(typeof(Base), "@scope/jsii-calc-base.Base")] + internal class BaseProxy : Base + { + private BaseProxy(ByRefValue reference): base(reference) + { + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/OperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/OperationProxy.cs new file mode 100644 index 0000000000..738b688952 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/OperationProxy.cs @@ -0,0 +1,27 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace +{ + /// Represents an operation on values. + [JsiiInterfaceProxy(typeof(Operation), "@scope/jsii-calc-lib.Operation")] + internal class OperationProxy : Operation + { + private OperationProxy(ByRefValue reference): base(reference) + { + } + + /// The value. + [JsiiProperty("value", "{\"primitive\":\"number\"}")] + public override double Value + { + get => GetInstanceProperty(); + } + + /// String representation of the value. + [JsiiMethod("toString", "{\"primitive\":\"string\"}", "[]")] + public override string ToString() + { + return InvokeInstanceMethod(new object[]{}); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/ValueProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/ValueProxy.cs new file mode 100644 index 0000000000..4042a5ed31 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/ValueProxy.cs @@ -0,0 +1,20 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace +{ + /// Abstract class which represents a numeric value. + [JsiiInterfaceProxy(typeof(Value_), "@scope/jsii-calc-lib.Value")] + internal class ValueProxy : Value_ + { + private ValueProxy(ByRefValue reference): base(reference) + { + } + + /// The value. + [JsiiProperty("value", "{\"primitive\":\"number\"}")] + public override double Value + { + get => GetInstanceProperty(); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassBaseProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassBaseProxy.cs new file mode 100644 index 0000000000..e18268ad8a --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassBaseProxy.cs @@ -0,0 +1,18 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + [JsiiInterfaceProxy(typeof(AbstractClassBase), "jsii-calc.AbstractClassBase")] + internal class AbstractClassBaseProxy : AbstractClassBase + { + private AbstractClassBaseProxy(ByRefValue reference): base(reference) + { + } + + [JsiiProperty("abstractProperty", "{\"primitive\":\"string\"}")] + public override string AbstractProperty + { + get => GetInstanceProperty(); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassProxy.cs new file mode 100644 index 0000000000..0640ddc205 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AbstractClassProxy.cs @@ -0,0 +1,24 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + [JsiiInterfaceProxy(typeof(AbstractClass), "jsii-calc.AbstractClass")] + internal class AbstractClassProxy : AbstractClass + { + private AbstractClassProxy(ByRefValue reference): base(reference) + { + } + + [JsiiProperty("abstractProperty", "{\"primitive\":\"string\"}")] + public override string AbstractProperty + { + get => GetInstanceProperty(); + } + + [JsiiMethod("abstractMethod", "{\"primitive\":\"string\"}", "[{\"name\":\"name\",\"type\":{\"primitive\":\"string\"}}]")] + public override string AbstractMethod(string name) + { + return InvokeInstanceMethod(new object[]{name}); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/BinaryOperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/BinaryOperationProxy.cs new file mode 100644 index 0000000000..0b057a43c8 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/BinaryOperationProxy.cs @@ -0,0 +1,27 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// Represents an operation with two operands. + [JsiiInterfaceProxy(typeof(BinaryOperation), "jsii-calc.BinaryOperation")] + internal class BinaryOperationProxy : BinaryOperation + { + private BinaryOperationProxy(ByRefValue reference): base(reference) + { + } + + /// The value. + [JsiiProperty("value", "{\"primitive\":\"number\"}")] + public override double Value + { + get => GetInstanceProperty(); + } + + /// String representation of the value. + [JsiiMethod("toString", "{\"primitive\":\"string\"}", "[]")] + public override string ToString() + { + return InvokeInstanceMethod(new object[]{}); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnaryOperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnaryOperationProxy.cs new file mode 100644 index 0000000000..2d748b3b58 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/UnaryOperationProxy.cs @@ -0,0 +1,27 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// An operation on a single operand. + [JsiiInterfaceProxy(typeof(UnaryOperation), "jsii-calc.UnaryOperation")] + internal class UnaryOperationProxy : UnaryOperation + { + private UnaryOperationProxy(ByRefValue reference): base(reference) + { + } + + /// The value. + [JsiiProperty("value", "{\"primitive\":\"number\"}")] + public override double Value + { + get => GetInstanceProperty(); + } + + /// String representation of the value. + [JsiiMethod("toString", "{\"primitive\":\"string\"}", "[]")] + public override string ToString() + { + return InvokeInstanceMethod(new object[]{}); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/composition/CompositeOperationProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/composition/CompositeOperationProxy.cs new file mode 100644 index 0000000000..6507f39c74 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/composition/CompositeOperationProxy.cs @@ -0,0 +1,24 @@ +using Amazon.JSII.Runtime.Deputy; +using Amazon.JSII.Tests.CalculatorNamespace.LibNamespace; + +namespace Amazon.JSII.Tests.CalculatorNamespace.composition +{ + /// Abstract operation composed from an expression of other operations. + [JsiiInterfaceProxy(typeof(CompositeOperation_), "jsii-calc.composition.CompositeOperation")] + internal class CompositeOperationProxy : CompositeOperation_ + { + private CompositeOperationProxy(ByRefValue reference): base(reference) + { + } + + /// + /// The expression that this operation consists of. + /// Must be implemented by derived classes. + /// + [JsiiProperty("expression", "{\"fqn\":\"@scope/jsii-calc-lib.Value\"}")] + public override Value_ Expression + { + get => GetInstanceProperty(); + } + } +} \ No newline at end of file