diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 9b238101..c3cf6f5a 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -31,7 +31,7 @@ namespace CppSharp.Generators.CSharp public TextGenerator ArgumentPrefix { get; private set; } public TextGenerator Cleanup { get; private set; } - public bool HasFixedBlock { get; set; } + public bool HasCodeBlock { get; set; } } public abstract class CSharpMarshalPrinter : MarshalPrinter @@ -420,7 +420,7 @@ namespace CppSharp.Generators.CSharp array.Type, ptr, Context.Parameter.Name); Context.SupportBefore.WriteStartBraceIndent(); Context.Return.Write("new global::System.IntPtr({0})", ptr); - Context.HasFixedBlock = true; + Context.HasCodeBlock = true; } else { @@ -495,7 +495,7 @@ namespace CppSharp.Generators.CSharp var refParamPtr = string.Format("__refParamPtr{0}", Context.ParameterIndex); Context.SupportBefore.WriteLine("fixed ({0} {1} = &{2})", pointer, refParamPtr, Context.Parameter.Name); - Context.HasFixedBlock = true; + Context.HasCodeBlock = true; Context.SupportBefore.WriteStartBraceIndent(); Context.Return.Write(refParamPtr); return true; diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 40e925ad..b513cbfe 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -955,6 +955,7 @@ namespace CppSharp.Generators.CSharp ctx.Kind = CSharpMarshalKind.NativeField; var marshal = new CSharpMarshalManagedToNativePrinter(ctx); + ctx.Declaration = field; var arrayType = field.Type as ArrayType; @@ -977,6 +978,9 @@ namespace CppSharp.Generators.CSharp if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); + if (ctx.HasCodeBlock) + PushIndent(); + if (marshal.Context.Return.StringBuilder.Length > 0) { WriteLine("{0} = {1}{2};", ctx.ReturnVarName, @@ -986,7 +990,7 @@ namespace CppSharp.Generators.CSharp marshal.Context.Return); } - if (arrayType != null && @class.IsValueType) + if ((arrayType != null && @class.IsValueType) || ctx.HasCodeBlock) WriteCloseBraceIndent(); WriteCloseBraceIndent(); @@ -1109,6 +1113,7 @@ namespace CppSharp.Generators.CSharp { Kind = CSharpMarshalKind.NativeField, ArgName = decl.Name, + Declaration = decl, ReturnVarName = string.Format("{0}{1}{2}", @class.IsValueType ? Helpers.InstanceField @@ -1129,6 +1134,9 @@ namespace CppSharp.Generators.CSharp if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); + if (ctx.HasCodeBlock) + PushIndent(); + var @return = marshal.Context.Return.ToString(); if (field.Type.IsPointer()) { @@ -1139,7 +1147,7 @@ namespace CppSharp.Generators.CSharp } WriteLine("return {0};", @return); - if (arrayType != null && @class.IsValueType) + if ((arrayType != null && @class.IsValueType) || ctx.HasCodeBlock) WriteCloseBraceIndent(); } else if (decl is Variable) @@ -2744,6 +2752,9 @@ namespace CppSharp.Generators.CSharp if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); + if (ctx.HasCodeBlock) + PushIndent(); + // Special case for indexer - needs to dereference if the internal // function is a pointer type and the property is not. if (retType.Type.IsAddress() && @@ -2752,12 +2763,15 @@ namespace CppSharp.Generators.CSharp WriteLine("return *{0};", marshal.Context.Return); else WriteLine("return {0};", marshal.Context.Return); + + if (ctx.HasCodeBlock) + WriteCloseBraceIndent(); } if (needsFixedThis && operatorParam == null) WriteCloseBraceIndent(); - var numFixedBlocks = @params.Count(param => param.HasFixedBlock); + var numFixedBlocks = @params.Count(param => param.HasUsingBlock); for(var i = 0; i < numFixedBlocks; ++i) WriteCloseBraceIndent(); } @@ -2838,7 +2852,7 @@ namespace CppSharp.Generators.CSharp public string Name; public Parameter Param; public CSharpMarshalContext Context; - public bool HasFixedBlock; + public bool HasUsingBlock; } public List GenerateFunctionParamsMarshal(IEnumerable @params, @@ -2896,7 +2910,7 @@ namespace CppSharp.Generators.CSharp paramMarshal.Context = ctx; var marshal = new CSharpMarshalManagedToNativePrinter(ctx); param.CSharpMarshalToNative(marshal); - paramMarshal.HasFixedBlock = ctx.HasFixedBlock; + paramMarshal.HasUsingBlock = ctx.HasCodeBlock; if (string.IsNullOrEmpty(marshal.Context.Return)) throw new Exception("Cannot marshal argument of function"); @@ -2904,7 +2918,7 @@ namespace CppSharp.Generators.CSharp if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); - if (paramMarshal.HasFixedBlock) + if (paramMarshal.HasUsingBlock) PushIndent(); WriteLine("var {0} = {1};", argName, marshal.Context.Return); diff --git a/src/Generator/Types/Std/Stdlib.cs b/src/Generator/Types/Std/Stdlib.cs index 547046c8..3157eaba 100644 --- a/src/Generator/Types/Std/Stdlib.cs +++ b/src/Generator/Types/Std/Stdlib.cs @@ -57,9 +57,10 @@ namespace CppSharp.Types.Std return basicString.Visit(typePrinter).Type; } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { - ClassTemplateSpecialization basicString = GetBasicString(ctx.Parameter.Type); + var type = ctx.Parameter.Type.Desugar(); + ClassTemplateSpecialization basicString = GetBasicString(type); var typePrinter = new CSharpTypePrinter(ctx.Driver); typePrinter.PushContext(CSharpTypePrinterContextKind.Native); if (!ctx.Parameter.Type.Desugar().IsAddress()) @@ -67,19 +68,46 @@ namespace CppSharp.Types.Std typePrinter.PopContext(); var allocator = ctx.Driver.ASTContext.FindClass("allocator", false, true).First( a => a.IsSupportedStdType()); - ctx.Return.Write("new {0}({1}, new {2}()).{3}", - basicString.Visit(typePrinter), ctx.Parameter.Name, - allocator.Visit(typePrinter), Helpers.InstanceIdentifier); + if (type.IsPointer() || (type.IsReference() && ctx.Declaration is Field)) + { + ctx.Return.Write("new {0}({1}, new {2}()).{3}", + basicString.Visit(typePrinter), ctx.Parameter.Name, + allocator.Visit(typePrinter), Helpers.InstanceIdentifier); + } + else + { + string varBasicString = "__basicString" + ctx.ParameterIndex; + ctx.SupportBefore.WriteLine("using (var {0} = new {1}({2}, new {3}()))", + varBasicString, basicString.Visit(typePrinter), + ctx.Parameter.Name, allocator.Visit(typePrinter)); + ctx.SupportBefore.WriteStartBraceIndent(); + ctx.Return.Write("{0}.{1}", varBasicString, Helpers.InstanceIdentifier); + ctx.HasCodeBlock = true; + } } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { - ClassTemplateSpecialization basicString = GetBasicString(ctx.ReturnType.Type); + var type = ctx.ReturnType.Type; + ClassTemplateSpecialization basicString = GetBasicString(type); var c_str = basicString.Methods.First(m => m.OriginalName == "c_str"); var typePrinter = new CSharpTypePrinter(ctx.Driver); - ctx.Return.Write("{0}.{1}({2}).{3}()", - basicString.Visit(typePrinter), Helpers.CreateInstanceIdentifier, - ctx.ReturnVarName, c_str.Name); + if (type.IsPointer() || ctx.Declaration is Field) + { + ctx.Return.Write("{0}.{1}({2}).{3}()", + basicString.Visit(typePrinter), Helpers.CreateInstanceIdentifier, + ctx.ReturnVarName, c_str.Name); + } + else + { + const string varBasicString = "__basicStringRet"; + ctx.SupportBefore.WriteLine("using (var {0} = {1}.{2}({3}))", + varBasicString, basicString.Visit(typePrinter), + Helpers.CreateInstanceIdentifier, ctx.ReturnVarName); + ctx.SupportBefore.WriteStartBraceIndent(); + ctx.Return.Write("{0}.{1}()", varBasicString, c_str.Name); + ctx.HasCodeBlock = true; + } } private static ClassTemplateSpecialization GetBasicString(Type type) @@ -114,12 +142,12 @@ namespace CppSharp.Types.Std return "string"; } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { ctx.Return.Write("new Std.WString()"); } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.ReturnVarName); } @@ -257,12 +285,12 @@ namespace CppSharp.Types.Std return string.Format("Std.Vector<{0}>", ctx.GetTemplateParameterList()); } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { ctx.Return.Write("{0}.Internal", ctx.Parameter.Name); } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { var templateType = Type as TemplateSpecializationType; var type = templateType.Arguments[0].Type; @@ -382,12 +410,12 @@ namespace CppSharp.Types.Std return CSharpTypePrinter.IntPtrType; } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.Parameter.Name); } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.ReturnVarName); } diff --git a/src/Generator/Types/TypeMap.cs b/src/Generator/Types/TypeMap.cs index 68eda684..b22b2842 100644 --- a/src/Generator/Types/TypeMap.cs +++ b/src/Generator/Types/TypeMap.cs @@ -67,12 +67,12 @@ namespace CppSharp.Types throw new NotImplementedException(); } - public virtual void CSharpMarshalToNative(MarshalContext ctx) + public virtual void CSharpMarshalToNative(CSharpMarshalContext ctx) { throw new NotImplementedException(); } - public virtual void CSharpMarshalToManaged(MarshalContext ctx) + public virtual void CSharpMarshalToManaged(CSharpMarshalContext ctx) { throw new NotImplementedException(); } diff --git a/tests/CSharp/CSharp.cs b/tests/CSharp/CSharp.cs index 19dca454..c1ac6966 100644 --- a/tests/CSharp/CSharp.cs +++ b/tests/CSharp/CSharp.cs @@ -29,7 +29,7 @@ namespace CppSharp.Tests return CSharpSignatureType(ctx).ToString(); } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { if (ctx.Parameter.Type.Desugar().IsAddress()) ctx.Return.Write("new global::System.IntPtr(&{0})", ctx.Parameter.Name); @@ -37,7 +37,7 @@ namespace CppSharp.Tests ctx.Return.Write(ctx.Parameter.Name); } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { if (ctx.ReturnType.Type.Desugar().IsAddress()) { @@ -89,13 +89,13 @@ namespace CppSharp.Tests ctx.GetTemplateParameterList()); } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { // pointless, put just so that the generated code compiles ctx.Return.Write("new QList.Internal()"); } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.ReturnVarName); } @@ -110,12 +110,12 @@ namespace CppSharp.Tests return "int"; } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.Parameter.Name); } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.ReturnVarName); } diff --git a/tests/Common/Common.Tests.cs b/tests/Common/Common.Tests.cs index 43b86ddf..4b1d61e5 100644 --- a/tests/Common/Common.Tests.cs +++ b/tests/Common/Common.Tests.cs @@ -407,11 +407,9 @@ public class CommonTests : GeneratorTestFixture public void TestVariable() { // Test field property - // HACK: disabled until https://github.com/mono/CppSharp/issues/675 is fixed. - // It used to work thanks to a hack in Common.cs which is now removed because it caused problems with system types - //var @var = new TestVariables(); - //@var.Value = 10; - //Assert.That(TestVariables.VALUE, Is.EqualTo(10)); + var @var = new TestVariables(); + @var.Value = 10; + Assert.That(TestVariables.VALUE, Is.EqualTo(10)); } [Test] @@ -635,6 +633,18 @@ public class CommonTests : GeneratorTestFixture } } + // ignored until we add automatic compilation for templates + [Test, Ignore] + public void TestStdString() + { + using (var hasStdString = new HasStdString()) + { + Assert.That(hasStdString.testStdString("test"), Is.EqualTo("test_test")); + hasStdString.s = "test"; + Assert.That(hasStdString.s, Is.EqualTo("test")); + } + } + private class CustomDerivedFromVirtual : AbstractWithVirtualDtor { public override void @abstract() diff --git a/tests/Common/Common.cs b/tests/Common/Common.cs index fd44c05e..cb08754e 100644 --- a/tests/Common/Common.cs +++ b/tests/Common/Common.cs @@ -32,12 +32,12 @@ namespace CppSharp.Tests return "ushort"; } - public override void CSharpMarshalToManaged(MarshalContext ctx) + public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) { ctx.Return.Write(ctx.ReturnVarName); } - public override void CSharpMarshalToNative(MarshalContext ctx) + public override void CSharpMarshalToNative(CSharpMarshalContext ctx) { ctx.Return.Write("IntPtr.Zero"); }