Browse Source

Fix a crash for secondary bases with secondary bases

The test has also uncovered a bug where the call to a primary base isn't always adjusted so the fix is extended accordingly.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1297/head
Dimitar Dobrev 5 years ago committed by João Matos
parent
commit
d3a3484c35
  1. 2
      src/Generator/Generators/CSharp/CSharpSources.cs
  2. 31
      src/Generator/Passes/MultipleInheritancePass.cs
  3. 19
      tests/CSharp/CSharp.Tests.cs
  4. 14
      tests/CSharp/CSharp.h

2
src/Generator/Generators/CSharp/CSharpSources.cs

@ -2945,7 +2945,7 @@ namespace CppSharp.Generators.CSharp
to = to.OriginalClass ?? to; to = to.OriginalClass ?? to;
baseOffset = GetOffsetToBase(from, to); baseOffset = GetOffsetToBase(from, to);
} }
var isPrimaryBase = from.BaseClass == to; var isPrimaryBase = (from.BaseClass?.OriginalClass ?? from.BaseClass) == to;
if (isPrimaryBase) if (isPrimaryBase)
{ {
return string.Format("({0} + {1}{2})", return string.Format("({0} + {1}{2})",

31
src/Generator/Passes/MultipleInheritancePass.cs

@ -15,6 +15,11 @@ namespace CppSharp.Passes
/// </summary> /// </summary>
private readonly HashSet<Class> interfaces = new HashSet<Class>(); private readonly HashSet<Class> interfaces = new HashSet<Class>();
/// <summary>
/// Change and implement secondaryy bases at the end to avoid processing implementations.
/// </summary>
private readonly HashSet<Class> classesWithSecondaryBases = new HashSet<Class>();
public MultipleInheritancePass() public MultipleInheritancePass()
{ {
VisitOptions.VisitClassFields = false; VisitOptions.VisitClassFields = false;
@ -35,26 +40,40 @@ namespace CppSharp.Passes
int index = @interface.Namespace.Declarations.IndexOf(@interface.OriginalClass); int index = @interface.Namespace.Declarations.IndexOf(@interface.OriginalClass);
@interface.Namespace.Declarations.Insert(index, @interface); @interface.Namespace.Declarations.Insert(index, @interface);
} }
foreach (Class @class in classesWithSecondaryBases)
{
for (var i = 1; i < @class.Bases.Count; i++)
{
var @base = @class.Bases[i];
Class @interface = interfaces.FirstOrDefault(iface => iface.OriginalClass == @base.Class);
if (@interface == null)
continue;
@class.Bases[i] = new BaseClassSpecifier(@base) { Type = new TagType(@interface) };
ImplementInterfaceMethods(@class, @interface);
ImplementInterfaceProperties(@class, @interface);
}
}
interfaces.Clear(); interfaces.Clear();
classesWithSecondaryBases.Clear();
return result; return result;
} }
public override bool VisitClassDecl(Class @class) public override bool VisitClassDecl(Class @class)
{ {
if (!base.VisitClassDecl(@class) || !@class.IsGenerated) if (!base.VisitClassDecl(@class) || !@class.IsGenerated || @class.Bases.Count == 1)
return false; return false;
classesWithSecondaryBases.Add(@class);
// skip the first base because we can inherit from one class // skip the first base because we can inherit from one class
for (var i = 1; i < @class.Bases.Count; i++) for (var i = 1; i < @class.Bases.Count; i++)
{ {
var @base = @class.Bases[i]; var @base = @class.Bases[i];
var baseClass = @base.Class; var baseClass = @base.Class;
if (baseClass == null || baseClass.IsInterface || !baseClass.IsGenerated) continue; if (baseClass == null || baseClass.IsInterface || !baseClass.IsGenerated) continue;
GetInterface(baseClass);
var @interface = GetInterface(baseClass);
@class.Bases[i] = new BaseClassSpecifier(@base) { Type = new TagType(@interface) };
ImplementInterfaceMethods(@class, @interface);
ImplementInterfaceProperties(@class, @interface);
} }
return true; return true;
} }

19
tests/CSharp/CSharp.Tests.cs

@ -371,13 +371,20 @@ public unsafe class CSharpTests : GeneratorTestFixture
[Test] [Test]
public void TestPrimarySecondaryBase() public void TestPrimarySecondaryBase()
{ {
var a = new MI_A0(); using (var a = new MI_A0())
var resa = a.Get(); {
Assert.That(resa, Is.EqualTo(50)); Assert.That(a.Get(), Is.EqualTo(50));
}
var c = new MI_C(); using (var c = new MI_C())
var res = c.Get(); {
Assert.That(res, Is.EqualTo(50)); Assert.That(c.Get(), Is.EqualTo(50));
}
using (var d = new MI_D())
{
Assert.That(d.Get(), Is.EqualTo(50));
}
} }
[Test] [Test]

14
tests/CSharp/CSharp.h

@ -580,6 +580,20 @@ struct DLL_API MI_C : public MI_A0, public MI_B
MI_C::MI_C() {} MI_C::MI_C() {}
struct DLL_API MI_A1
{
MI_A1();
};
MI_A1::MI_A1() {}
struct DLL_API MI_D : public MI_A1, public MI_C
{
MI_D();
};
MI_D::MI_D() {}
class DLL_API StructWithPrivateFields class DLL_API StructWithPrivateFields
{ {
public: public:

Loading…
Cancel
Save