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

31
src/Generator/Passes/MultipleInheritancePass.cs

@ -15,6 +15,11 @@ namespace CppSharp.Passes @@ -15,6 +15,11 @@ namespace CppSharp.Passes
/// </summary>
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()
{
VisitOptions.VisitClassFields = false;
@ -35,26 +40,40 @@ namespace CppSharp.Passes @@ -35,26 +40,40 @@ namespace CppSharp.Passes
int index = @interface.Namespace.Declarations.IndexOf(@interface.OriginalClass);
@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();
classesWithSecondaryBases.Clear();
return result;
}
public override bool VisitClassDecl(Class @class)
{
if (!base.VisitClassDecl(@class) || !@class.IsGenerated)
if (!base.VisitClassDecl(@class) || !@class.IsGenerated || @class.Bases.Count == 1)
return false;
classesWithSecondaryBases.Add(@class);
// skip the first base because we can inherit from one class
for (var i = 1; i < @class.Bases.Count; i++)
{
var @base = @class.Bases[i];
var baseClass = @base.Class;
if (baseClass == null || baseClass.IsInterface || !baseClass.IsGenerated) continue;
var @interface = GetInterface(baseClass);
@class.Bases[i] = new BaseClassSpecifier(@base) { Type = new TagType(@interface) };
ImplementInterfaceMethods(@class, @interface);
ImplementInterfaceProperties(@class, @interface);
GetInterface(baseClass);
}
return true;
}

19
tests/CSharp/CSharp.Tests.cs

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

14
tests/CSharp/CSharp.h

@ -580,6 +580,20 @@ struct DLL_API MI_C : public MI_A0, public MI_B @@ -580,6 +580,20 @@ struct DLL_API MI_C : public MI_A0, public MI_B
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
{
public:

Loading…
Cancel
Save