From 77f45dee38d75c881c7c09db284198ad31412bf0 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Thu, 27 Oct 2016 20:53:10 +0300 Subject: [PATCH] Fixed the adjustment of the instance in cases of multiple inheritance. Fixes https://github.com/mono/CppSharp/issues/707. Signed-off-by: Dimitar Dobrev --- .../Generators/CSharp/CSharpSources.cs | 18 ++++++++++++----- .../Passes/MultipleInheritancePass.cs | 15 +++++++++----- tests/CSharp/CSharp.Tests.cs | 2 ++ tests/CSharp/CSharp.cpp | 20 ++++++++++++++++++- tests/CSharp/CSharp.h | 10 +++++++++- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index ea2ee1b2..40303e10 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -2513,7 +2513,12 @@ namespace CppSharp.Generators.CSharp private void GetVirtualCallDelegate(Method method, Class @class, out string delegateId) { - var i = VTables.GetVTableIndex(method.OriginalFunction ?? method, @class); + Function @virtual = method; + if (method.OriginalFunction != null && + !((Class) method.OriginalFunction.Namespace).IsInterface) + @virtual = method.OriginalFunction; + + var i = VTables.GetVTableIndex(@virtual, @class); int vtableIndex = 0; if (Context.ParserOptions.IsMicrosoftAbi) vtableIndex = @class.Layout.VFTables.IndexOf(@class.Layout.VFTables.Where( @@ -2526,7 +2531,7 @@ namespace CppSharp.Generators.CSharp WriteStartBraceIndent(); } - var @delegate = GetVTableMethodDelegateName(method.OriginalFunction ?? method); + var @delegate = GetVTableMethodDelegateName(@virtual); delegateId = Generator.GeneratedIdentifier(@delegate); WriteLine("var {0} = ({1}) Marshal.GetDelegateForFunctionPointer(new IntPtr({2}), typeof({1}));", @@ -2823,11 +2828,14 @@ namespace CppSharp.Generators.CSharp WriteCloseBraceIndent(); } - private static string GetInstanceParam(Function function) + private string GetInstanceParam(Function function) { var from = (Class) function.Namespace; - var to = function.OriginalFunction == null ? @from.BaseClass : - (Class) function.OriginalFunction.Namespace; + var to = function.OriginalFunction == null || + // we don't need to offset the instance with Itanium if there's an existing interface impl + (Context.ParserOptions.IsItaniumLikeAbi && + !((Class) function.OriginalNamespace).IsInterface) ? + @from.BaseClass : (Class) function.OriginalFunction.Namespace; var baseOffset = 0u; if (to != null) diff --git a/src/Generator/Passes/MultipleInheritancePass.cs b/src/Generator/Passes/MultipleInheritancePass.cs index c379e3d3..443fb918 100644 --- a/src/Generator/Passes/MultipleInheritancePass.cs +++ b/src/Generator/Passes/MultipleInheritancePass.cs @@ -160,15 +160,20 @@ namespace CppSharp.Passes return interfaceProperty; } - private static void ImplementInterfaceMethods(Class @class, Class @interface) + private void ImplementInterfaceMethods(Class @class, Class @interface) { foreach (var method in @interface.Methods) { - if (@class.Methods.Any(m => m.OriginalName == method.OriginalName && - m.Parameters.Where(p => !p.Ignore).SequenceEqual( - method.Parameters.Where(p => !p.Ignore), - ParameterTypeComparer.Instance))) + var existingImpl = @class.Methods.FirstOrDefault( + m => m.OriginalName == method.OriginalName && + m.Parameters.Where(p => !p.Ignore).SequenceEqual( + method.Parameters.Where(p => !p.Ignore), + ParameterTypeComparer.Instance)); + if (existingImpl != null) + { + existingImpl.OriginalFunction = method; continue; + } var impl = new Method(method) { Namespace = @class, diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/CSharp/CSharp.Tests.cs index 86939716..fa949419 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/CSharp/CSharp.Tests.cs @@ -647,6 +647,8 @@ public unsafe class CSharpTests : GeneratorTestFixture { Assert.That(implementsAbstractsFromPrimaryAndSecondary.AbstractInPrimaryBase, Is.EqualTo(101)); Assert.That(implementsAbstractsFromPrimaryAndSecondary.AbstractInSecondaryBase, Is.EqualTo(5)); + Assert.That(implementsAbstractsFromPrimaryAndSecondary.AbstractReturnsFieldInPrimaryBase, Is.EqualTo(201)); + Assert.That(implementsAbstractsFromPrimaryAndSecondary.AbstractReturnsFieldInSecondaryBase, Is.EqualTo(202)); } } diff --git a/tests/CSharp/CSharp.cpp b/tests/CSharp/CSharp.cpp index ada200e4..9d9074cb 100644 --- a/tests/CSharp/CSharp.cpp +++ b/tests/CSharp/CSharp.cpp @@ -1222,7 +1222,15 @@ void HasMissingObjectOnVirtualCall::setMissingObjectOnVirtualCall(MissingObjectO stackOverflowOnVirtualCall = value; } -ImplementsAbstractsFromPrimaryAndSecondary::ImplementsAbstractsFromPrimaryAndSecondary() +AbstractPrimaryBase::~AbstractPrimaryBase() +{ +} + +AbstractSecondaryBase::~AbstractSecondaryBase() +{ +} + +ImplementsAbstractsFromPrimaryAndSecondary::ImplementsAbstractsFromPrimaryAndSecondary() : field(200) { } @@ -1239,3 +1247,13 @@ int ImplementsAbstractsFromPrimaryAndSecondary::abstractInSecondaryBase() { return 5; } + +int ImplementsAbstractsFromPrimaryAndSecondary::abstractReturnsFieldInPrimaryBase() +{ + return field + 1; +} + +int ImplementsAbstractsFromPrimaryAndSecondary::abstractReturnsFieldInSecondaryBase() +{ + return field + 2; +} diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h index 910fd8f4..aefbd3a3 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/CSharp/CSharp.h @@ -1095,20 +1095,28 @@ private: class DLL_API AbstractPrimaryBase { public: + virtual ~AbstractPrimaryBase(); virtual int abstractInPrimaryBase() = 0; + virtual int abstractReturnsFieldInPrimaryBase() = 0; }; class DLL_API AbstractSecondaryBase { public: + virtual ~AbstractSecondaryBase(); virtual int abstractInSecondaryBase() = 0; + virtual int abstractReturnsFieldInSecondaryBase() = 0; }; class DLL_API ImplementsAbstractsFromPrimaryAndSecondary : public AbstractPrimaryBase, public AbstractSecondaryBase { public: ImplementsAbstractsFromPrimaryAndSecondary(); - ~ImplementsAbstractsFromPrimaryAndSecondary(); + virtual ~ImplementsAbstractsFromPrimaryAndSecondary(); virtual int abstractInPrimaryBase(); virtual int abstractInSecondaryBase(); + virtual int abstractReturnsFieldInPrimaryBase(); + virtual int abstractReturnsFieldInSecondaryBase(); +private: + int field; };