From 30cb2cbe854007ce88dffcd96564ca9cfc8824f7 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 22 Oct 2014 17:04:33 +0300 Subject: [PATCH] Fixed an ambiguity between an internal ctor and a potential wrapped one. Signed-off-by: Dimitar Dobrev --- .../Generators/CSharp/CSharpMarshal.cs | 9 ++-- .../Generators/CSharp/CSharpTextTemplate.cs | 49 +++++++++++-------- tests/CSharpTemp/CSharpTemp.Tests.cs | 8 +++ tests/CSharpTemp/CSharpTemp.cpp | 21 ++++++++ tests/CSharpTemp/CSharpTemp.h | 11 +++++ 5 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index e5a714ec..cf0d74ff 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -256,10 +256,11 @@ namespace CppSharp.Generators.CSharp "Internal" : ""); if (returnType.IsAddress()) - Context.Return.Write("({0} == IntPtr.Zero) ? {1} : ", instance, - @class.IsRefType ? "null" : string.Format("new {0}()", type)); - - Context.Return.Write("new {0}({1})", type, instance); + Context.Return.Write("({0} == IntPtr.Zero) ? {1} : {2}.{3}({0})", instance, + @class.IsRefType ? "null" : string.Format("new {0}()", type), + type, Helpers.CreateInstanceIdentifier); + else + Context.Return.Write("new {0}({1})", type, instance); return true; } diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index cce96644..53b62365 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -45,6 +45,8 @@ namespace CppSharp.Generators.CSharp public const string AllocatedWithHGlobalIdentifier = "__allocatedWithHGlobal"; + public const string CreateInstanceIdentifier = "__CreateInstance"; + public static string GetAccess(AccessSpecifier accessSpecifier) { switch (accessSpecifier) @@ -1889,32 +1891,36 @@ namespace CppSharp.Generators.CSharp PopBlock(NewLineKind.BeforeNextBlock); } - PushBlock(CSharpBlockKind.Method); string className = @class.Name; string safeIdentifier = className; - if (@class.Access == AccessSpecifier.Private && className.EndsWith("Internal")) + bool isAbstractImpl = @class.Methods.Any(m => m.SynthKind == FunctionSynthKind.AbstractImplCall); + if (isAbstractImpl) { className = className.Substring(0, safeIdentifier.LastIndexOf("Internal", StringComparison.Ordinal)); } - WriteLine("internal {0}({1}.Internal* native)", safeIdentifier, - className); - WriteLineIndent(": this(new global::System.IntPtr(native))"); - WriteStartBraceIndent(); - WriteCloseBraceIndent(); - PopBlock(NewLineKind.BeforeNextBlock); + + if (!@class.IsAbstract) + { + PushBlock(CSharpBlockKind.Method); + WriteLine("public static {0} {1}(global::System.IntPtr native)", safeIdentifier, Helpers.CreateInstanceIdentifier); + WriteStartBraceIndent(); + WriteLine("return new {0}(({1}.Internal*) native);", safeIdentifier, className); + WriteCloseBraceIndent(); + PopBlock(NewLineKind.BeforeNextBlock); + } GenerateNativeConstructorByValue(@class, className, safeIdentifier); PushBlock(CSharpBlockKind.Method); - WriteLine("public {0}(global::System.IntPtr native, bool isInternalImpl = false){1}", - safeIdentifier, @class.IsValueType ? " : this()" : string.Empty); + WriteLine("{0} {1}({2}.Internal* native, bool isInternalImpl = false){3}", + @class.IsRefType ? "protected" : "private", + safeIdentifier, className, @class.IsValueType ? " : this()" : string.Empty); var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType; if (hasBaseClass) - WriteLineIndent(": base(native{0})", - @class.Methods.Any(m => m.SynthKind == FunctionSynthKind.AbstractImplCall) ? - ", true" : string.Empty); + WriteLineIndent(": base(({0}.Internal*) native{1})", + @class.BaseClass.Name, isAbstractImpl ? ", true" : string.Empty); WriteStartBraceIndent(); @@ -1922,13 +1928,13 @@ namespace CppSharp.Generators.CSharp { if (ShouldGenerateClassNativeField(@class)) { - WriteLine("{0} = native;", Helpers.InstanceIdentifier); + WriteLine("{0} = new global::System.IntPtr(native);", Helpers.InstanceIdentifier); GenerateVTableClassSetupCall(@class, true); } } else { - WriteLine("var {0} = (Internal*){1}.ToPointer();", + WriteLine("var {0} = {1};", Generator.GeneratedIdentifier("ptr"), "native"); GenerateStructMarshalingProperties(@class); } @@ -1960,7 +1966,7 @@ namespace CppSharp.Generators.CSharp if (@class.IsRefType) { PushBlock(CSharpBlockKind.Method); - WriteLine("private static global::System.IntPtr __CopyValue({0}.Internal native)", className); + WriteLine("private static {0}.Internal* __CopyValue({0}.Internal native)", className); WriteStartBraceIndent(); if (@class.HasNonTrivialCopyConstructor) { @@ -1975,12 +1981,13 @@ namespace CppSharp.Generators.CSharp WriteLine("var ret = Marshal.AllocHGlobal({0});", @class.Layout.Size); WriteLine("{0}.Internal.{1}(ret, new global::System.IntPtr(&native));", QualifiedIdentifier(@class), GetFunctionNativeIdentifier(copyCtorMethod)); - WriteLine("return ret;"); + WriteLine("return ({0}.Internal*) ret;", className); } else { - WriteLine("global::System.IntPtr ret = Marshal.AllocHGlobal({0});", @class.Layout.Size); - WriteLine("*({0}.Internal*) ret = native;", className); + WriteLine("{0}.Internal* ret = ({0}.Internal*) Marshal.AllocHGlobal({1});", + className, @class.Layout.Size); + WriteLine("*ret = native;", className); WriteLine("return ret;"); } WriteCloseBraceIndent(); @@ -1988,7 +1995,7 @@ namespace CppSharp.Generators.CSharp } PushBlock(CSharpBlockKind.Method); WriteLine("internal {0}({1}.Internal native)", safeIdentifier, className); - WriteLineIndent(@class.IsRefType ? ": this(__CopyValue(native))" : ": this(&native)", className); + WriteLineIndent(@class.IsRefType ? ": this(__CopyValue(native))" : ": this(&native)"); WriteStartBraceIndent(); if (@class.IsRefType) { @@ -2008,7 +2015,7 @@ namespace CppSharp.Generators.CSharp Write(": this("); if (method != null) - Write("IntPtr.Zero"); + Write("(Internal*) null"); else Write("native"); diff --git a/tests/CSharpTemp/CSharpTemp.Tests.cs b/tests/CSharpTemp/CSharpTemp.Tests.cs index 9288feb2..4bdd777e 100644 --- a/tests/CSharpTemp/CSharpTemp.Tests.cs +++ b/tests/CSharpTemp/CSharpTemp.Tests.cs @@ -172,4 +172,12 @@ public class CSharpTempTests : GeneratorTestFixture Assert.AreEqual(q1.Array[i], q2.Array[i]); } } + + [Test] + public void TestInternalCtorAmbiguity() + { + using (new InternalCtorAmbiguity().InvokeInternalCtor()) + { + } + } } \ No newline at end of file diff --git a/tests/CSharpTemp/CSharpTemp.cpp b/tests/CSharpTemp/CSharpTemp.cpp index 52ab08c2..d00df5ae 100644 --- a/tests/CSharpTemp/CSharpTemp.cpp +++ b/tests/CSharpTemp/CSharpTemp.cpp @@ -298,3 +298,24 @@ void PropertyWithIgnoredType::setIgnoredType(const IgnoredType &value) { _ignoredType = value; } + +InternalCtorAmbiguity::InternalCtorAmbiguity() : copy(0) +{ +} + +InternalCtorAmbiguity::InternalCtorAmbiguity(void* param) : copy(0) +{ + // cause a crash to indicate this is the incorrect ctor to invoke + throw; +} + +InternalCtorAmbiguity* InternalCtorAmbiguity::InvokeInternalCtor() +{ + return copy = new InternalCtorAmbiguity(); +} + +InternalCtorAmbiguity::~InternalCtorAmbiguity() +{ + if (copy) + delete copy; +} diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index 28b931ea..3e8ece09 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -264,3 +264,14 @@ public: private: IgnoredType _ignoredType; }; + +class DLL_API InternalCtorAmbiguity +{ +public: + InternalCtorAmbiguity(); + InternalCtorAmbiguity(void* param); + InternalCtorAmbiguity* InvokeInternalCtor(); + ~InternalCtorAmbiguity(); +private: + InternalCtorAmbiguity* copy; +};