diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 5c700740..cfb3bc53 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -11,8 +11,12 @@ using CppSharp.AST.Extensions; using CppSharp.Passes; using CppSharp.Types; using CppSharp.Utils; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Attribute = CppSharp.AST.Attribute; using Type = CppSharp.AST.Type; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.CSharp; namespace CppSharp.Generators.CSharp { @@ -53,17 +57,17 @@ namespace CppSharp.Generators.CSharp public static readonly string CreateInstanceIdentifier = Generator.GeneratedIdentifier("CreateInstance"); - public static string GetAccess(AccessSpecifier accessSpecifier) + public static SyntaxKind GetAccess(AccessSpecifier accessSpecifier) { switch (accessSpecifier) { case AccessSpecifier.Private: case AccessSpecifier.Internal: - return "internal "; + return SyntaxKind.InternalKeyword; case AccessSpecifier.Protected: - return "protected "; + return SyntaxKind.ProtectedKeyword; default: - return "public "; + return SyntaxKind.PublicKeyword; } } } @@ -121,136 +125,130 @@ namespace CppSharp.Generators.CSharp public override void Process() { - GenerateHeader(); + compilationUnit = SyntaxFactory.CompilationUnit(); + + compilationUnit = compilationUnit.AddUsings( + SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System")), + SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System.Runtime.InteropServices")), + SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System.Security"))); - PushBlock(CSharpBlockKind.Usings); - WriteLine("using System;"); - WriteLine("using System.Runtime.InteropServices;"); - WriteLine("using System.Security;"); foreach (var customUsingStatement in Options.DependentNameSpaces) { - WriteLine(string.Format("using {0};", customUsingStatement)); + compilationUnit = compilationUnit.AddUsings( + SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName(customUsingStatement))); } - PopBlock(NewLineKind.BeforeNextBlock); + var members = TranslationUnits.SelectMany(unit => GenerateDeclContext(unit)).ToArray(); + if (Options.GenerateLibraryNamespace) { - PushBlock(CSharpBlockKind.Namespace); - WriteLine("namespace {0}", Driver.Options.OutputNamespace); - WriteStartBraceIndent(); + var root = SyntaxFactory.NamespaceDeclaration( + SyntaxFactory.IdentifierName(Driver.Options.OutputNamespace)); + root = AddMembers(root, members); + compilationUnit = AddMembers(compilationUnit, new [] { root }); } - - foreach (var unit in TranslationUnits) + else { - GenerateDeclContext(unit); + compilationUnit = AddMembers(compilationUnit, members); } - if (Options.GenerateLibraryNamespace) + GenerateHeader(); + } + + public override void Generate(TextWriter textWriter) + { + using (var workspace = new AdhocWorkspace()) { - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + var formattedNode = Formatter.Format(compilationUnit, workspace); + formattedNode.WriteTo(textWriter); } } - public void GenerateHeader() + private void GenerateHeader() { - PushBlock(BlockKind.Header); - WriteLine("//----------------------------------------------------------------------------"); - WriteLine("// This is autogenerated code by CppSharp."); - WriteLine("// Do not edit this file or all your changes will be lost after re-generation."); - WriteLine("//----------------------------------------------------------------------------"); - PopBlock(); + compilationUnit = compilationUnit.WithLeadingTrivia( + SyntaxFactory.Comment("//----------------------------------------------------------------------------"), + SyntaxFactory.CarriageReturnLineFeed, + SyntaxFactory.Comment("// This is autogenerated code by CppSharp."), + SyntaxFactory.CarriageReturnLineFeed, + SyntaxFactory.Comment("// Do not edit this file or all your changes will be lost after re-generation."), + SyntaxFactory.CarriageReturnLineFeed, + SyntaxFactory.Comment("//----------------------------------------------------------------------------"), + SyntaxFactory.CarriageReturnLineFeed); } - private void GenerateDeclContext(DeclarationContext context) + private MemberDeclarationSyntax[] GenerateDeclContext(DeclarationContext context) { var isNamespace = context is Namespace; var isTranslationUnit = context is TranslationUnit; - var shouldGenerateNamespace = isNamespace && !isTranslationUnit; - - if (shouldGenerateNamespace) - { - PushBlock(CSharpBlockKind.Namespace); - WriteLine("namespace {0}", context.Name); - WriteStartBraceIndent(); - } - - // Generate all the enum declarations. - foreach (var @enum in context.Enums) - { - if (!@enum.IsGenerated || @enum.IsIncomplete) - continue; + var members = new List(); - GenerateEnum(@enum); - } - - // Generate all the typedef declarations. - foreach (var typedef in context.Typedefs) - { - GenerateTypedef(typedef); - } + members.AddRange( + from @enum in context.Enums + where @enum.IsGenerated && !@enum.IsIncomplete + select GenerateEnum(@enum)); - // Generate all the struct/class declarations. - foreach (var @class in context.Classes) + members.AddRange(context.Typedefs.Select(t => GenerateTypedef(t)).Where(t => t != null)); + + foreach (var @class in context.Classes.Where(c => !c.IsIncomplete)) { - if (@class.IsIncomplete) - continue; - if (@class.IsInterface) - GenerateInterface(@class); + members.Add(GenerateInterface(@class)); else - GenerateClass(@class); + members.Add(GenerateClass(@class)); } - if (context.HasFunctions) - { - PushBlock(CSharpBlockKind.Functions); - WriteLine("public unsafe partial class {0}", - context.TranslationUnit.FileNameWithoutExtension); - WriteStartBraceIndent(); + //if (context.HasFunctions) + //{ + // PushBlock(CSharpBlockKind.Functions); + // WriteLine("public unsafe partial class {0}", + // context.TranslationUnit.FileNameWithoutExtension); + // WriteStartBraceIndent(); - PushBlock(CSharpBlockKind.InternalsClass); - GenerateClassInternalHead(); - WriteStartBraceIndent(); + // PushBlock(CSharpBlockKind.InternalsClass); + // GenerateClassInternalHead(); + // WriteStartBraceIndent(); - // Generate all the internal function declarations. - foreach (var function in context.Functions) - { - if ((!function.IsGenerated && !function.IsInternal) || function.IsSynthetized) continue; + // // Generate all the internal function declarations. + // foreach (var function in context.Functions) + // { + // if ((!function.IsGenerated && !function.IsInternal) || function.IsSynthetized) continue; - GenerateInternalFunction(function); - } + // GenerateInternalFunction(function); + // } - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + // WriteCloseBraceIndent(); + // PopBlock(NewLineKind.BeforeNextBlock); - foreach (var function in context.Functions) - { - if (!function.IsGenerated) continue; + // foreach (var function in context.Functions) + // { + // if (!function.IsGenerated) continue; - GenerateFunction(function); - } + // GenerateFunction(function); + // } - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); - } + // WriteCloseBraceIndent(); + // PopBlock(NewLineKind.BeforeNextBlock); + //} - foreach (var @event in context.Events) - { - if (!@event.IsGenerated) continue; + //foreach (var @event in context.Events) + //{ + // if (!@event.IsGenerated) continue; - GenerateEvent(@event); - } + // GenerateEvent(@event); + //} - foreach(var childNamespace in context.Namespaces) - GenerateDeclContext(childNamespace); + members.AddRange(context.Namespaces.SelectMany(n => GenerateDeclContext(n))); - if (shouldGenerateNamespace) + if (isNamespace && !isTranslationUnit) { - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + var @namespace = SyntaxFactory.NamespaceDeclaration( + SyntaxFactory.IdentifierName(context.Name)); + return new [] { AddMembers(@namespace, members.ToArray()) }; } + + return members.ToArray(); } public void GenerateDeclarationCommon(Declaration decl) @@ -318,10 +316,13 @@ namespace CppSharp.Generators.CSharp #region Classes - public void GenerateClass(Class @class) + public MemberDeclarationSyntax GenerateClass(Class @class) { - if (@class.IsIncomplete) - return; + //GenerateDeclarationCommon(@class); + + MemberDeclarationSyntax type = GenerateClassProlog(@class); + if (@class.IsOpaque) + return type; System.Type typeMap = null; if (Driver.TypeDatabase.TypeMaps.ContainsKey(@class.Name)) @@ -331,73 +332,116 @@ namespace CppSharp.Generators.CSharp Driver.TypeDatabase.TypeMaps.Remove(@class.Name); } - PushBlock(CSharpBlockKind.Class); - GenerateDeclarationCommon(@class); - - GenerateClassProlog(@class); + if (!@class.IsAbstractImpl) + type = AddMembers(type, GenerateClassInternals(@class)); + type = AddMembers(type, GenerateDeclContext(@class)); - NewLine(); - WriteStartBraceIndent(); + if (@class.IsDependent || !@class.IsGenerated) + goto exit; - if (!@class.IsOpaque) + if (ShouldGenerateClassNativeField(@class)) { - if (!@class.IsAbstractImpl) - GenerateClassInternals(@class); - GenerateDeclContext(@class); + if (@class.IsValueType) + { + type = AddMembers(type, GenerateStructNativeField(@class)); + } + else + { + type = AddMembers(type, GenerateClassNativeField(@class)); + } + } - if (@class.IsDependent || !@class.IsGenerated) - goto exit; + //if (Options.GenerateClassMarshals) + //{ + // GenerateClassMarshals(@class); + //} - if (ShouldGenerateClassNativeField(@class)) - { - PushBlock(CSharpBlockKind.Field); - if (@class.IsValueType) - { - WriteLine("private {0}.Internal {1};", @class.Name, Helpers.InstanceField); - WriteLine("public {0}.Internal {1} {{ get {{ return {2}; }} }}", @class.Name, - Helpers.InstanceIdentifier, Helpers.InstanceField); - } - else - { - WriteLine("public {0} {1} {{ get; protected set; }}", - "global::System.IntPtr", Helpers.InstanceIdentifier); + if (!@class.IsStatic) + type = AddMembers(type, GenerateClassConstructors(@class)); - PopBlock(NewLineKind.BeforeNextBlock); + //GenerateClassMethods(@class.Methods); + //GenerateClassVariables(@class); + //GenerateClassProperties(@class); - PushBlock(CSharpBlockKind.Field); + //if (@class.IsDynamic) + // GenerateVTable(@class); + exit: - WriteLine("protected int {0};", Helpers.PointerAdjustmentIdentifier); + if (typeMap != null) + Driver.TypeDatabase.TypeMaps.Add(@class.Name, typeMap); - // use interfaces if any - derived types with a secondary base this class must be compatible with the map - var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class); - WriteLine( - "public static readonly System.Collections.Concurrent.ConcurrentDictionary NativeToManagedMap = new System.Collections.Concurrent.ConcurrentDictionary();", - @interface != null ? @interface.Name : @class.Name); - WriteLine("protected void*[] __OriginalVTables;"); - } - PopBlock(NewLineKind.BeforeNextBlock); - } + return type; + } - if (Options.GenerateClassMarshals) - { - GenerateClassMarshals(@class); - } + private MemberDeclarationSyntax[] GenerateStructNativeField(Class @class) + { + var members = new List(); - GenerateClassConstructors(@class); + var internalType = string.Format("{0}.Internal", @class.Name); - GenerateClassMethods(@class.Methods); - GenerateClassVariables(@class); - GenerateClassProperties(@class); + members.Add(SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration( + SyntaxFactory.ParseTypeName(internalType)) + .AddVariables(SyntaxFactory.VariableDeclarator(Helpers.InstanceField))) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword))); - if (@class.IsDynamic) - GenerateVTable(@class); - } - exit: - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + members.Add(SyntaxFactory.PropertyDeclaration( + SyntaxFactory.ParseTypeName(internalType), Helpers.InstanceIdentifier) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( + SyntaxKind.GetAccessorDeclaration, + SyntaxFactory.Block(SyntaxFactory.ReturnStatement( + SyntaxFactory.IdentifierName(Helpers.InstanceField)))))); - if (typeMap != null) - Driver.TypeDatabase.TypeMaps.Add(@class.Name, typeMap); + return members.ToArray(); + } + + private MemberDeclarationSyntax[] GenerateClassNativeField(Class @class) + { + var members = new List(); + + members.Add(SyntaxFactory.PropertyDeclaration( + SyntaxFactory.ParseTypeName("global::System.IntPtr"), Helpers.InstanceIdentifier) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( + SyntaxKind.GetAccessorDeclaration).WithSemicolonToken( + SyntaxFactory.Token(SyntaxKind.SemicolonToken)), + SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)))); + + members.Add(SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration( + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword))) + .AddVariables(SyntaxFactory.VariableDeclarator( + Helpers.PointerAdjustmentIdentifier))) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))); + + // use interfaces if any - derived types with a secondary base this class must be compatible with the map + var name = (@class.Namespace.Classes.Find(c => c.OriginalClass == @class) ?? @class).Name; + var dictionaryType = string.Format( + "System.Collections.Concurrent.ConcurrentDictionary", name); + members.Add(SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration( + SyntaxFactory.ParseTypeName(dictionaryType)) + .AddVariables(SyntaxFactory.VariableDeclarator("NativeToManagedMap") + .WithInitializer( + SyntaxFactory.EqualsValueClause(SyntaxFactory.ObjectCreationExpression( + SyntaxFactory.ParseTypeName(dictionaryType), + SyntaxFactory.ArgumentList(), null))))) + .AddModifiers( + SyntaxFactory.Token(SyntaxKind.PublicKeyword), + SyntaxFactory.Token(SyntaxKind.StaticKeyword), + SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword))); + + members.Add(SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration( + SyntaxFactory.ArrayType( + SyntaxFactory.PointerType( + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword))) + .WithAsteriskToken(SyntaxFactory.Token(SyntaxKind.AsteriskToken))) + .AddRankSpecifiers(SyntaxFactory.ArrayRankSpecifier())) + .AddVariables(SyntaxFactory.VariableDeclarator( + SyntaxFactory.Identifier("__OriginalVTables")))) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))); + + return members.ToArray(); } private void GenerateClassMarshals(Class @class) @@ -419,83 +463,81 @@ namespace CppSharp.Generators.CSharp NewLine(); } - private void GenerateInterface(Class @class) + private TypeDeclarationSyntax GenerateInterface(Class @class) { - if (!@class.IsGenerated || @class.IsIncomplete) - return; + //GenerateDeclarationCommon(@class); - PushBlock(CSharpBlockKind.Interface); - GenerateDeclarationCommon(@class); + return GenerateClassProlog(@class); - GenerateClassProlog(@class); + //foreach (var method in @class.Methods.Where(m => + // !ASTUtils.CheckIgnoreMethod(m, Options) && m.Access == AccessSpecifier.Public)) + //{ + // PushBlock(CSharpBlockKind.Method); + // GenerateDeclarationCommon(method); - NewLine(); - WriteStartBraceIndent(); + // var functionName = GetMethodIdentifier(method); - foreach (var method in @class.Methods.Where(m => - !ASTUtils.CheckIgnoreMethod(m, Options) && m.Access == AccessSpecifier.Public)) - { - PushBlock(CSharpBlockKind.Method); - GenerateDeclarationCommon(method); + // Write("{0} {1}(", method.OriginalReturnType, functionName); - var functionName = GetMethodIdentifier(method); + // Write(FormatMethodParameters(method.Parameters)); - Write("{0} {1}(", method.OriginalReturnType, functionName); - - Write(FormatMethodParameters(method.Parameters)); - - WriteLine(");"); - - PopBlock(NewLineKind.BeforeNextBlock); - } - foreach (var prop in @class.Properties.Where(p => p.IsGenerated && p.Access == AccessSpecifier.Public)) - { - PushBlock(CSharpBlockKind.Property); - var type = prop.Type; - if (prop.Parameters.Count > 0 && prop.Type.IsPointerToPrimitiveType()) - type = ((PointerType) prop.Type).Pointee; - GenerateDeclarationCommon(prop); - Write("{0} {1} {{ ", type, GetPropertyName(prop)); - if (prop.HasGetter) - Write("get; "); - if (prop.HasSetter) - Write("set; "); + // WriteLine(");"); - WriteLine("}"); - PopBlock(NewLineKind.BeforeNextBlock); - } + // PopBlock(NewLineKind.BeforeNextBlock); + //} + //foreach (var prop in @class.Properties.Where(p => p.IsGenerated && p.Access == AccessSpecifier.Public)) + //{ + // PushBlock(CSharpBlockKind.Property); + // var type = prop.Type; + // if (prop.Parameters.Count > 0 && prop.Type.IsPointerToPrimitiveType()) + // type = ((PointerType) prop.Type).Pointee; + // GenerateDeclarationCommon(prop); + // Write("{0} {1} {{ ", type, GetPropertyName(prop)); + // if (prop.HasGetter) + // Write("get; "); + // if (prop.HasSetter) + // Write("set; "); - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + // WriteLine("}"); + // PopBlock(NewLineKind.BeforeNextBlock); + //} } - public void GenerateClassInternals(Class @class) + public MemberDeclarationSyntax GenerateClassInternals(Class @class) { - PushBlock(CSharpBlockKind.InternalsClass); - WriteLine("[StructLayout(LayoutKind.Explicit, Size = {0})]", - @class.Layout.Size); + var @struct = SyntaxFactory.StructDeclaration("Internal").AddModifiers( + SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddAttributeLists(SyntaxFactory.AttributeList().AddAttributes( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("StructLayout"), + SyntaxFactory.AttributeArgumentList().AddArguments( + SyntaxFactory.AttributeArgument( + SyntaxFactory.IdentifierName("LayoutKind.Explicit")), + SyntaxFactory.AttributeArgument( + SyntaxFactory.IdentifierName("Size = " + @class.Layout.Size)))))); - GenerateClassInternalHead(@class); - WriteStartBraceIndent(); + if (@class != null && @class.NeedsBase && !@class.BaseClass.IsInterface) + @struct = @struct.AddModifiers(SyntaxFactory.Token(SyntaxKind.NewKeyword)); + + @struct = @struct.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)); TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); - GenerateClassFields(@class, @class, GenerateClassInternalsField, true); + @struct = AddMembers(@struct, + GenerateClassFields(@class, @class, GenerateClassInternalsField, true)); if (@class.IsGenerated) { if (@class.IsDynamic) - GenerateVTablePointers(@class); + @struct = AddMembers(@struct, GenerateVTablePointers(@class)); var functions = GatherClassInternalFunctions(@class); - foreach (var function in functions) - GenerateInternalFunction(function); + @struct = AddMembers(@struct, + functions.Where(f => !f.IsPure).Select(f => GenerateInternalFunction(f)).ToArray()); } TypePrinter.PopContext(); - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + return @struct; } private IEnumerable GatherClassInternalFunctions(Class @class, @@ -581,16 +623,6 @@ namespace CppSharp.Generators.CSharp return @params; } - private void GenerateClassInternalHead(Class @class = null) - { - Write("public "); - - if (@class != null && @class.NeedsBase && !@class.BaseClass.IsInterface) - Write("new "); - - WriteLine("partial struct Internal"); - } - public static bool ShouldGenerateClassNativeField(Class @class) { if (@class.IsStatic) @@ -598,25 +630,31 @@ namespace CppSharp.Generators.CSharp return @class.IsValueType || !@class.HasBase || !@class.HasRefBase(); } - public void GenerateClassProlog(Class @class) + public TypeDeclarationSyntax GenerateClassProlog(Class @class) { - Write(@class.IsInternal ? "internal " : Helpers.GetAccess(@class.Access)); + TypeDeclarationSyntax type; + if (@class.IsInterface) + type = SyntaxFactory.InterfaceDeclaration(@class.Name); + else if (@class.IsValueType) + type = SyntaxFactory.StructDeclaration(@class.Name); + else + type = SyntaxFactory.ClassDeclaration(@class.Name); + + type = AddModifier(type, @class.IsInternal ? + SyntaxKind.InternalKeyword : Helpers.GetAccess(@class.Access)); if (@class.Access == AccessSpecifier.Protected) - Write("internal "); - Write("unsafe "); + type = AddModifier(type, SyntaxKind.InternalKeyword); + type = AddModifier(type, SyntaxKind.UnsafeKeyword); if (@class.IsAbstract) - Write("abstract "); + type = AddModifier(type, SyntaxKind.AbstractKeyword); if (@class.IsStatic) - Write("static "); + type = AddModifier(type, SyntaxKind.StaticKeyword); // This token needs to directly precede the "class" token. if (Options.GeneratePartialClasses) - Write("partial "); - - Write(@class.IsInterface ? "interface " : (@class.IsValueType ? "struct " : "class ")); - Write("{0}", @class.Name); + type = AddModifier(type, SyntaxKind.PartialKeyword); var bases = new List(); @@ -628,24 +666,26 @@ namespace CppSharp.Generators.CSharp select @base.Class.Visit(TypePrinter).Type); } + if (!@class.IsStatic) + foreach (var @base in bases) + type = AddBase(type, @base); + if (@class.IsGenerated) { if (@class.IsRefType) - bases.Add("IDisposable"); + type = AddBase(type,"IDisposable"); if (Options.GenerateClassMarshals) - { - bases.Add("CppSharp.Runtime.ICppMarshal"); - } + type = AddBase(type, "CppSharp.Runtime.ICppMarshal"); } - if (bases.Count > 0 && !@class.IsStatic) - Write(" : {0}", string.Join(", ", bases)); + return type; } - public void GenerateClassFields(Class owner, Class @class, - Action action, bool nativeFields = false) + public MemberDeclarationSyntax[] GenerateClassFields(Class owner, Class @class, + Func function, bool nativeFields = false) { + var members = new List(); foreach (var @base in @class.Bases.Where(b => b.Class != null)) { TypeMap typeMap; @@ -653,64 +693,74 @@ namespace CppSharp.Generators.CSharp @base.Class.OriginalClass == @class) continue; - GenerateClassFields(owner, @base.Class, action, nativeFields); + members.AddRange(GenerateClassFields(owner, @base.Class, function, nativeFields)); } foreach (var field in @class.Fields) { if (ASTUtils.CheckIgnoreField(field, nativeFields)) continue; - action(owner, field); + members.AddRange(function(owner, field)); } + + return members.ToArray(); } - private void GenerateClassInternalsField(Class owner, Field field) + private MemberDeclarationSyntax[] GenerateClassInternalsField(Class owner, Field field) { // we do not support dependent fields yet, see https://github.com/mono/CppSharp/issues/197 Class @class; field.Type.TryGetClass(out @class); if ((field.Type.IsDependent && !field.Type.IsPointer() && !(@class != null && @class.IsUnion)) || (@class != null && @class.TranslationUnit.IsSystemHeader)) - return; + return new MemberDeclarationSyntax[0]; - var safeIdentifier = Helpers.SafeIdentifier(field.InternalName); + var members = new List(); + var safeIdentifier = Helpers.SafeIdentifier(field.InternalName); if(safeIdentifier.All(c => c.Equals('_'))) { safeIdentifier = Helpers.SafeIdentifier(field.Name); } - PushBlock(CSharpBlockKind.Field); - - WriteLine("[FieldOffset({0})]", field.OffsetInBytes + - owner.ComputeNonVirtualBaseClassOffsetTo((Class) field.Namespace)); - TypePrinter.PushMarshalKind(CSharpMarshalKind.NativeField); var fieldTypePrinted = field.QualifiedType.CSharpType(TypePrinter); TypePrinter.PopMarshalKind(); - var typeName = safeIdentifier; + var fieldName = safeIdentifier; if (!string.IsNullOrWhiteSpace(fieldTypePrinted.NameSuffix)) - typeName += fieldTypePrinted.NameSuffix; + fieldName += fieldTypePrinted.NameSuffix; - var access = @class != null && !@class.IsGenerated ? "internal" : "public"; + var offset = (int) field.OffsetInBytes + + owner.ComputeNonVirtualBaseClassOffsetTo((Class) field.Namespace); + var access = @class != null && !@class.IsGenerated ? + SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword; + + var variable = SyntaxFactory.VariableDeclarator(fieldName); if (field.Expression != null) { - var fieldValuePrinted = field.Expression.CSharpValue(ExpressionPrinter); - Write("{0} {1} {2} = {3};", access, fieldTypePrinted.Type, typeName, fieldValuePrinted); - } - else - { - Write("{0} {1} {2};", access, fieldTypePrinted.Type, typeName); + var fieldValuePrinted = field.Expression.CSharpValue(ExpressionPrinter).Value; + variable = variable.WithInitializer( + SyntaxFactory.EqualsValueClause(SyntaxFactory.IdentifierName(fieldValuePrinted))); } - PopBlock(NewLineKind.BeforeNextBlock); + var fieldDeclaration = (SyntaxFactory.FieldDeclaration( + SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName(fieldTypePrinted.Type)) + .AddVariables(variable)) + .AddModifiers(SyntaxFactory.Token(access)) + .AddAttributeLists(SyntaxFactory.AttributeList().AddAttributes( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("FieldOffset")) + .AddArgumentListArguments(SyntaxFactory.AttributeArgument( + SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal(offset))))))); // Workaround a bug in Mono when handling fixed arrays in P/Invoke declarations. // https://bugzilla.xamarin.com/show_bug.cgi?id=33571 var arrayType = field.Type.Desugar() as ArrayType; - if (arrayType != null && arrayType.SizeType == ArrayType.ArraySize.Constant && - arrayType.Size > 0) + if (arrayType != null && arrayType.SizeType == ArrayType.ArraySize.Constant) { + fieldDeclaration = fieldDeclaration.AddModifiers( + SyntaxFactory.Token(SyntaxKind.FixedKeyword)); for (var i = 1; i < arrayType.Size; ++i) { var dummy = new Field @@ -722,9 +772,12 @@ namespace CppSharp.Generators.CSharp Namespace = owner }; - GenerateClassInternalsField(owner, dummy); + members.AddRange(GenerateClassInternalsField(owner, dummy)); } } + + members.Insert(0, fieldDeclaration); + return members.ToArray(); } private void GenerateClassField(Field field, bool @public = false) @@ -1164,7 +1217,7 @@ namespace CppSharp.Generators.CSharp GenerateDeclarationCommon(prop); if (prop.ExplicitInterfaceImpl == null) { - Write(Helpers.GetAccess(GetValidPropertyAccess(prop))); + //Write(Helpers.GetAccess(GetValidPropertyAccess(prop))); if (prop.IsStatic) Write("static "); @@ -1605,30 +1658,38 @@ namespace CppSharp.Generators.CSharp return string.Format("_{0}Delegate", nativeId); } - public void GenerateVTablePointers(Class @class) + public MemberDeclarationSyntax[] GenerateVTablePointers(Class @class) { + var members = new List(); + if (Options.IsMicrosoftAbi) { - var index = 0; - foreach (var info in @class.Layout.VFTables) + for (int i = 0; i < @class.Layout.VFTables.Count; i++) { - PushBlock(CSharpBlockKind.InternalsClassField); - - WriteLine("[FieldOffset({0})]", info.VFPtrFullOffset); - WriteLine("public global::System.IntPtr vfptr{0};", index++); - - PopBlock(NewLineKind.BeforeNextBlock); + var vFPtrFullOffset = (int) @class.Layout.VFTables[i].VFPtrFullOffset; + members.Add(VTablePointer(i, vFPtrFullOffset)); } } else { - PushBlock(CSharpBlockKind.InternalsClassField); + members.Add(VTablePointer(0, 0)); + } - WriteLine("[FieldOffset(0)]"); - WriteLine("public global::System.IntPtr vfptr0;"); + return members.ToArray(); + } - PopBlock(NewLineKind.BeforeNextBlock); - } + private FieldDeclarationSyntax VTablePointer(int i, int offset) + { + return SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration( + SyntaxFactory.ParseTypeName("global::System.IntPtr")).AddVariables( + SyntaxFactory.VariableDeclarator("vfptr" + i))) + .AddAttributeLists(SyntaxFactory.AttributeList().AddAttributes( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("FieldOffset")) + .AddArgumentListArguments(SyntaxFactory.AttributeArgument( + SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal(offset)))))) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); } #endregion @@ -1740,25 +1801,25 @@ namespace CppSharp.Generators.CSharp #region Constructors - public void GenerateClassConstructors(Class @class) + public MemberDeclarationSyntax[] GenerateClassConstructors(Class @class) { - if (@class.IsStatic) - return; + var members = new List(); // Output a default constructor that takes the native pointer. - GenerateNativeConstructor(@class); + members.AddRange(GenerateNativeConstructor(@class)); - foreach (var ctor in @class.Constructors) - { - if (ASTUtils.CheckIgnoreMethod(ctor, Options)) - continue; + //foreach (var ctor in @class.Constructors) + //{ + // if (ASTUtils.CheckIgnoreMethod(ctor, Options)) + // continue; - GenerateMethod(ctor, @class); - } + // GenerateMethod(ctor, @class); + //} if (@class.IsRefType) { - GenerateClassFinalizer(@class); + if (Options.GenerateFinalizers) + members.Add(GenerateClassFinalizer(@class)); // ensure any virtual dtor in the chain is called var dtor = @class.Destructors.FirstOrDefault(d => d.Access != AccessSpecifier.Private && d.IsVirtual); @@ -1768,129 +1829,130 @@ namespace CppSharp.Generators.CSharp // virtual destructors in abstract classes may lack a pointer in the v-table // so they have to be called by symbol; thus we need an explicit Dispose override @class.IsAbstract) - GenerateDisposeMethods(@class); + members.AddRange(GenerateDisposeMethods(@class)); } + + return members.ToArray(); } - private void GenerateClassFinalizer(INamedDecl @class) + private MemberDeclarationSyntax GenerateClassFinalizer(INamedDecl @class) { - if (!Options.GenerateFinalizers) - return; - - PushBlock(CSharpBlockKind.Finalizer); - - WriteLine("~{0}()", @class.Name); - WriteStartBraceIndent(); - WriteLine("Dispose(false);"); - WriteCloseBraceIndent(); - - PopBlock(NewLineKind.BeforeNextBlock); + return SyntaxFactory.DestructorDeclaration(@class.Name).AddBodyStatements( + SyntaxFactory.ParseStatement("Dispose(false)")); } - private void GenerateDisposeMethods(Class @class) + private IEnumerable GenerateDisposeMethods(Class @class) { + var members = new List(); + var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType; // Generate the IDispose Dispose() method. if (!hasBaseClass) { - PushBlock(CSharpBlockKind.Method); - WriteLine("public void Dispose()"); - WriteStartBraceIndent(); - - WriteLine("Dispose(disposing: true);"); + var dispose = SyntaxFactory.MethodDeclaration( + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), "Dispose") + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddBodyStatements(SyntaxFactory.ParseStatement("Dispose(disposing: true);")); + if (Options.GenerateFinalizers) - WriteLine("GC.SuppressFinalize(this);"); - - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + dispose = dispose.AddBodyStatements( + SyntaxFactory.ParseStatement("GC.SuppressFinalize(this);")); + members.Add(dispose); } // Generate Dispose(bool) method - PushBlock(CSharpBlockKind.Method); - if (@class.IsValueType) - { - Write("private "); - } - else - { - Write("protected "); - Write(hasBaseClass ? "override " : "virtual "); - } - - WriteLine("void Dispose(bool disposing)"); - WriteStartBraceIndent(); - WriteLine("if (!{0} && disposing)", Helpers.OwnsNativeInstanceIdentifier); - WriteLineIndent("throw new global::System.InvalidOperationException" + - "(\"Managed instances owned by native code cannot be disposed of.\");"); + var disposeBool = SyntaxFactory.MethodDeclaration( + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), "Dispose") + .AddModifiers(SyntaxFactory.Token( + @class.IsValueType ? SyntaxKind.PrivateKeyword : SyntaxKind.ProtectedKeyword)) + .AddParameterListParameters( + SyntaxFactory.Parameter(SyntaxFactory.Identifier("disposing")).WithType( + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword)))) + .AddBodyStatements(); if (@class.IsRefType) - { - var @base = @class.GetNonIgnoredRootBase(); - - // Use interfaces if any - derived types with a this class as a seconary base, must be compatible with the map - var @interface = @base.Namespace.Classes.Find(c => c.OriginalClass == @base); - - // The local var must be of the exact type in the object map because of TryRemove - WriteLine("{0} {1};", - (@interface ?? (@base.IsAbstractImpl ? @base.BaseClass : @base)).Visit(TypePrinter), - Helpers.DummyIdentifier); - WriteLine("NativeToManagedMap.TryRemove({0}, out {1});", - Helpers.InstanceIdentifier, Helpers.DummyIdentifier); - if (@class.IsDynamic && GetUniqueVTableMethodEntries(@class).Count != 0) - { - if (Options.IsMicrosoftAbi) - for (var i = 0; i < @class.Layout.VFTables.Count; i++) - WriteLine("((Internal*) {0})->vfptr{1} = new global::System.IntPtr(__OriginalVTables[{1}]);", - Helpers.InstanceIdentifier, i); - else - WriteLine("((Internal*) {0})->vfptr0 = new global::System.IntPtr(__OriginalVTables[0]);", - Helpers.InstanceIdentifier); - } - } - - var dtor = @class.Destructors.FirstOrDefault(); - if (dtor != null && dtor.Access != AccessSpecifier.Private && - @class.HasNonTrivialDestructor && !dtor.IsPure) - { - NativeLibrary library; - if (!Options.CheckSymbols || - Driver.Symbols.FindLibraryBySymbol(dtor.Mangled, out library)) - { - if (dtor.IsVirtual) - { - GenerateVirtualFunctionCall(dtor, @class, true); - if (@class.IsAbstract) - { - WriteCloseBraceIndent(); - WriteLine("else"); - PushIndent(); - GenerateInternalFunctionCall(dtor); - PopIndent(); - } - } - else - GenerateInternalFunctionCall(dtor); - } - } - - WriteLine("if ({0})", Helpers.OwnsNativeInstanceIdentifier); - WriteLineIndent("Marshal.FreeHGlobal({0});", Helpers.InstanceIdentifier); - - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); - } + disposeBool = disposeBool.AddModifiers(SyntaxFactory.Token( + hasBaseClass ? SyntaxKind.OverrideKeyword : SyntaxKind.VirtualKeyword)); + + members.Add(disposeBool); + + //WriteLine("if (!{0} && disposing)", Helpers.OwnsNativeInstanceIdentifier); + //WriteLineIndent("throw new global::System.InvalidOperationException" + + // "(\"Managed instances owned by native code cannot be disposed of.\");"); + + //if (@class.IsRefType) + //{ + // var @base = @class.GetNonIgnoredRootBase(); + + // // Use interfaces if any - derived types with a this class as a seconary base, must be compatible with the map + // var @interface = @base.Namespace.Classes.Find(c => c.OriginalClass == @base); + + // // The local var must be of the exact type in the object map because of TryRemove + // WriteLine("{0} {1};", + // (@interface ?? (@base.IsAbstractImpl ? @base.BaseClass : @base)).Visit(TypePrinter), + // Helpers.DummyIdentifier); + // WriteLine("NativeToManagedMap.TryRemove({0}, out {1});", + // Helpers.InstanceIdentifier, Helpers.DummyIdentifier); + // if (@class.IsDynamic && GetUniqueVTableMethodEntries(@class).Count != 0) + // { + // if (Options.IsMicrosoftAbi) + // for (var i = 0; i < @class.Layout.VFTables.Count; i++) + // WriteLine("((Internal*) {0})->vfptr{1} = new global::System.IntPtr(__OriginalVTables[{1}]);", + // Helpers.InstanceIdentifier, i); + // else + // WriteLine("((Internal*) {0})->vfptr0 = new global::System.IntPtr(__OriginalVTables[0]);", + // Helpers.InstanceIdentifier); + // } + //} + + //var dtor = @class.Destructors.FirstOrDefault(); + //if (dtor != null && dtor.Access != AccessSpecifier.Private && + // @class.HasNonTrivialDestructor && !dtor.IsPure) + //{ + // NativeLibrary library; + // if (!Options.CheckSymbols || + // Driver.Symbols.FindLibraryBySymbol(dtor.Mangled, out library)) + // { + // if (dtor.IsVirtual) + // { + // GenerateVirtualFunctionCall(dtor, @class, true); + // if (@class.IsAbstract) + // { + // WriteCloseBraceIndent(); + // WriteLine("else"); + // PushIndent(); + // GenerateInternalFunctionCall(dtor); + // PopIndent(); + // } + // } + // else + // GenerateInternalFunctionCall(dtor); + // } + //} + + //WriteLine("if ({0})", Helpers.OwnsNativeInstanceIdentifier); + //WriteLineIndent("Marshal.FreeHGlobal({0});", Helpers.InstanceIdentifier); + + return members; + } + + private MemberDeclarationSyntax[] GenerateNativeConstructor(Class @class) + { + var members = new List(); - private void GenerateNativeConstructor(Class @class) - { var shouldGenerateClassNativeField = ShouldGenerateClassNativeField(@class); if (@class.IsRefType && shouldGenerateClassNativeField) { - PushBlock(CSharpBlockKind.Field); - WriteLine("protected bool {0};", Helpers.OwnsNativeInstanceIdentifier); - PopBlock(NewLineKind.BeforeNextBlock); + members.Add(SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration( + SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword))) + .AddVariables( + SyntaxFactory.VariableDeclarator(Helpers.OwnsNativeInstanceIdentifier))) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))); } + return members.ToArray(); + var className = @class.IsAbstractImpl ? @class.BaseClass.Name : @class.Name; var ctorCall = string.Format("{0}{1}", @class.Name, @class.IsAbstract ? "Internal" : ""); @@ -2075,7 +2137,7 @@ namespace CppSharp.Generators.CSharp if (method.ExplicitInterfaceImpl == null) { - Write(Helpers.GetAccess(GetValidMethodAccess(method))); + //Write(Helpers.GetAccess(GetValidMethodAccess(method))); } // check if overriding a function from a secondary base @@ -2809,12 +2871,12 @@ namespace CppSharp.Generators.CSharp #endregion - public bool GenerateTypedef(TypedefDecl typedef) + public MemberDeclarationSyntax GenerateTypedef(TypedefDecl typedef) { if (!typedef.IsGenerated) - return false; + return null; - GenerateDeclarationCommon(typedef); + //GenerateDeclarationCommon(typedef); FunctionType functionType; TagType tag; @@ -2822,74 +2884,81 @@ namespace CppSharp.Generators.CSharp if (typedef.Type.IsPointerToPrimitiveType(PrimitiveType.Void) || typedef.Type.IsPointerTo(out tag)) { - PushBlock(CSharpBlockKind.Typedef); - WriteLine("public class " + typedef.Name + @" { }"); - PopBlock(NewLineKind.BeforeNextBlock); + return SyntaxFactory.ClassDeclaration(typedef.Name).AddModifiers( + SyntaxFactory.Token(SyntaxKind.PublicKeyword)); } - else if (typedef.Type.IsPointerTo(out functionType)) + if (!typedef.Type.IsPointerTo(out functionType)) { - PushBlock(CSharpBlockKind.Typedef); - var attributedType = typedef.Type.GetPointee() as AttributedType; - var callingConvention = attributedType == null - ? functionType.CallingConvention - : ((FunctionType) attributedType.Equivalent.Type).CallingConvention; - TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); - var interopCallConv = callingConvention.ToInteropCallConv(); - if (interopCallConv != System.Runtime.InteropServices.CallingConvention.Winapi) - WriteLine( - "[SuppressUnmanagedCodeSecurity, " + - "UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]", - interopCallConv); - WriteLine("{0}unsafe {1};", - Helpers.GetAccess(typedef.Access), - string.Format(TypePrinter.VisitDelegate(functionType).Type, - typedef.Name)); - TypePrinter.PopContext(); - PopBlock(NewLineKind.BeforeNextBlock); + return null; } - return true; + return GenerateDelegate(typedef, functionType); } - public void GenerateEnum(Enumeration @enum) + private MemberDeclarationSyntax GenerateDelegate(TypedefDecl typedef, FunctionType functionType) { - if (!@enum.IsGenerated) return; + var attributedType = typedef.Type.GetPointee() as AttributedType; + var callingConvention = attributedType == null + ? functionType.CallingConvention + : ((FunctionType) attributedType.Equivalent.Type).CallingConvention; - PushBlock(CSharpBlockKind.Enum); - GenerateDeclarationCommon(@enum); - - if (@enum.IsFlags) - WriteLine("[Flags]"); - - Write("public enum {0}", @enum.Name); - - var typeName = TypePrinter.VisitPrimitiveType(@enum.BuiltinType.Type, - new TypeQualifiers()); + var attributes = new List(2) + { + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("SuppressUnmanagedCodeSecurity")) + }; + var interopCallConv = callingConvention.ToInteropCallConv(); + if (interopCallConv != System.Runtime.InteropServices.CallingConvention.Winapi) + attributes.Add( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("UnmanagedFunctionPointerAttribute"), + SyntaxFactory.AttributeArgumentList().AddArguments( + SyntaxFactory.AttributeArgument( + SyntaxFactory.IdentifierName( + "global::System.Runtime.InteropServices.CallingConvention." + + interopCallConv))))); - if (@enum.BuiltinType.Type != PrimitiveType.Int) - Write(" : {0}", typeName); + TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); + var @delegate = SyntaxFactory.DelegateDeclaration( + SyntaxFactory.ParseTypeName(functionType.ReturnType.Visit(TypePrinter).Type), + typedef.Name).AddAttributeLists( + SyntaxFactory.AttributeList().AddAttributes(attributes.ToArray())) + .AddModifiers( + SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.UnsafeKeyword)) + .AddParameterListParameters( + (from parameter in functionType.Parameters + select SyntaxFactory.Parameter( + SyntaxFactory.Identifier(parameter.Name)).WithType( + SyntaxFactory.ParseTypeName(parameter.Type.Visit(TypePrinter).Type))).ToArray()); + TypePrinter.PopContext(); - NewLine(); + return @delegate; + } - WriteStartBraceIndent(); - for (var i = 0; i < @enum.Items.Count; ++i) + public EnumDeclarationSyntax GenerateEnum(Enumeration @enum) + { + var @enumDeclaration = SyntaxFactory.EnumDeclaration(@enum.Name).AddModifiers( + SyntaxFactory.Token(Helpers.GetAccess(@enum.Access))); + if (@enum.IsFlags) { - var item = @enum.Items[i]; - GenerateInlineSummary(item.Comment); - - var value = @enum.GetItemValueAsString(item); - Write(item.ExplicitValue - ? string.Format("{0} = {1}", item.Name, value) - : string.Format("{0}", item.Name)); - - if (i < @enum.Items.Count - 1) - Write(","); + enumDeclaration = enumDeclaration.AddAttributeLists( + SyntaxFactory.AttributeList().AddAttributes( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("Flags")))); + } - NewLine(); + foreach (var item in @enum.Items) + { + var enumMember = SyntaxFactory.EnumMemberDeclaration(item.Name); + if (item.ExplicitValue) + { + var value = @enum.GetItemValueAsString(item); + enumMember = enumMember.WithEqualsValue( + SyntaxFactory.EqualsValueClause(SyntaxFactory.IdentifierName(value))); + } + enumDeclaration = enumDeclaration.AddMembers(enumMember); } - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + return enumDeclaration; + + //GenerateDeclarationCommon(@enum); } public static string GetMethodIdentifier(Method method) @@ -2942,16 +3011,13 @@ namespace CppSharp.Generators.CSharp return identifier; } - public void GenerateInternalFunction(Function function) + public MemberDeclarationSyntax GenerateInternalFunction(Function function) { - if (function.IsPure) - return; - if (function.OriginalFunction != null) function = function.OriginalFunction; - PushBlock(CSharpBlockKind.InternalsClassMethod); - WriteLine("[SuppressUnmanagedCodeSecurity]"); + CSharpTypePrinterResult retType; + var @params = GatherInternalParams(function, out retType); string libName = Options.SharedLibraryName; @@ -2973,25 +3039,106 @@ namespace CppSharp.Generators.CSharp if (Options.GenerateInternalImports) libName = "__Internal"; - Write("[DllImport(\"{0}\", ", libName); - var callConv = function.CallingConvention.ToInteropCallConv(); - WriteLine("CallingConvention = global::System.Runtime.InteropServices.CallingConvention.{0},", - callConv); - WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled); + return SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName(retType.Type), + GetFunctionNativeIdentifier(function)) + .AddAttributeLists(SyntaxFactory.AttributeList().AddAttributes( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("SuppressUnmanagedCodeSecurity")))) + .AddAttributeLists(SyntaxFactory.AttributeList().AddAttributes( + SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("DllImport")) + .AddArgumentListArguments( + SyntaxFactory.AttributeArgument(SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(libName))), + SyntaxFactory.AttributeArgument(SyntaxFactory.IdentifierName( + "CallingConvention = global::System.Runtime.InteropServices.CallingConvention." + callConv)), + SyntaxFactory.AttributeArgument( + SyntaxFactory.IdentifierName(string.Format("EntryPoint=\"{0}\"", function.Mangled)))))) + .AddModifiers( + SyntaxFactory.Token(SyntaxKind.InternalKeyword), + SyntaxFactory.Token(SyntaxKind.StaticKeyword), + SyntaxFactory.Token(SyntaxKind.ExternKeyword)) + .AddParameterListParameters( + (@params.Select(p => SyntaxFactory.Parameter(SyntaxFactory.Identifier(p))).ToArray())) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); if (function.ReturnType.Type.IsPrimitiveType(PrimitiveType.Bool)) WriteLine("[return: MarshalAsAttribute(UnmanagedType.I1)]"); + } - CSharpTypePrinterResult retType; - var @params = GatherInternalParams(function, out retType); + private T AddMembers(T parent, params MemberDeclarationSyntax[] members) where T : CSharpSyntaxNode + { + var compilationUnitSyntax = parent as CompilationUnitSyntax; + if (compilationUnitSyntax != null) + { + return compilationUnitSyntax.AddMembers(members) as T; + } - WriteLine("internal static extern {0} {1}({2});", retType, - GetFunctionNativeIdentifier(function), - string.Join(", ", @params)); - PopBlock(NewLineKind.BeforeNextBlock); + var @namespace = parent as NamespaceDeclarationSyntax; + if (@namespace != null) + { + return @namespace.AddMembers(members) as T; + } + + var @class = parent as ClassDeclarationSyntax; + if (@class != null) + { + return @class.AddMembers(members) as T; + } + + var @struct = parent as StructDeclarationSyntax; + if (@struct != null) + { + return @struct.AddMembers(members) as T; + } + + var @interface = parent as InterfaceDeclarationSyntax; + if (@interface != null) + { + return @interface.AddMembers(members) as T; + } + + return parent; } + + private T AddModifier(T parent, SyntaxKind modifier) where T : CSharpSyntaxNode + { + var @class = parent as ClassDeclarationSyntax; + if (@class != null) + return @class.AddModifiers(SyntaxFactory.Token(modifier)) as T; + + var @struct = parent as StructDeclarationSyntax; + if (@struct != null) + return @struct.AddModifiers(SyntaxFactory.Token(modifier)) as T; + + var @interface = parent as InterfaceDeclarationSyntax; + if (@interface != null) + return @interface.AddModifiers(SyntaxFactory.Token(modifier)) as T; + + return parent; + } + + private T AddBase(T parent, string @base) where T : CSharpSyntaxNode + { + var @class = parent as ClassDeclarationSyntax; + if (@class != null) + return @class.AddBaseListTypes( + SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(@base))) as T; + + var @struct = parent as StructDeclarationSyntax; + if (@struct != null) + return @struct.AddBaseListTypes( + SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(@base))) as T; + + var @interface = parent as InterfaceDeclarationSyntax; + if (@interface != null) + return @interface.AddBaseListTypes( + SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(@base))) as T; + + return parent; + } + + private CompilationUnitSyntax compilationUnit; } internal class SymbolNotFoundException : Exception diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index 949abd5c..bb63b086 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -139,16 +139,14 @@ namespace CppSharp.Generators.CSharp { return new CSharpTypePrinterResult() { - Type = "fixed byte", + Type = "byte", NameSuffix = string.Format("[{0}]", array.Size * @class.Layout.Size) }; } - // Do not write the fixed keyword multiple times for nested array types - var fixedKeyword = array.Type is ArrayType ? string.Empty : "fixed "; return new CSharpTypePrinterResult() { - Type = string.Format("{0}{1}", fixedKeyword, array.Type.Visit(this, quals)), + Type = array.Type.Visit(this, quals).Type, NameSuffix = string.Format("[{0}]", array.Size) }; }