Browse Source

Implemented virtual function call handling.

Closes issues #402, #496.

Thanks to Abhinav for his pull which I based this work on.
pull/552/merge
triton 10 years ago
parent
commit
e2b74a7697
  1. 31
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  2. 15
      tests/Common/Common.cpp
  3. 13
      tests/Common/Common.h
  4. 47
      tests/VTables/VTables.Tests.cs
  5. 26
      tests/VTables/VTables.cpp
  6. 15
      tests/VTables/VTables.h

31
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -2191,6 +2191,10 @@ namespace CppSharp.Generators.CSharp @@ -2191,6 +2191,10 @@ namespace CppSharp.Generators.CSharp
{
GenerateAbstractImplCall(method, @class.BaseClass);
}
else if (method.IsVirtual)
{
GenerateVirtualFunctionCall(method, @class);
}
else
{
GenerateInternalFunctionCall(method);
@ -2344,6 +2348,33 @@ namespace CppSharp.Generators.CSharp @@ -2344,6 +2348,33 @@ namespace CppSharp.Generators.CSharp
return virtualCallBuilder.ToString();
}
private void GenerateVirtualFunctionCall(Method function, Class @class)
{
string delegateId, @delegate;
Write(GetVirtualCallDelegate(function, @class, out delegateId, out @delegate));
GenerateFunctionCall(delegateId, function.Parameters, function);
}
public string GetVirtualCallDelegate(Method function, Class @class,
out string delegateId, out string @delegate)
{
var virtualCallBuilder = new StringBuilder();
var i = VTables.GetVTableIndex(function, @class);
virtualCallBuilder.AppendFormat("void* slot = *(void**) ((IntPtr)__OriginalVTables[0] + {0} * {1});",
i, Driver.TargetInfo.PointerWidth / 8);
virtualCallBuilder.AppendLine();
@delegate = GetVTableMethodDelegateName(function.OriginalFunction ?? function);
delegateId = Generator.GeneratedIdentifier(@delegate);
virtualCallBuilder.AppendFormat(
"var {1} = ({0}) Marshal.GetDelegateForFunctionPointer(new IntPtr(slot), typeof({0}));",
@delegate, delegateId);
virtualCallBuilder.AppendLine();
return virtualCallBuilder.ToString();
}
private void GenerateOperator(Method method)
{
if (method.SynthKind == FunctionSynthKind.ComplementOperator)

15
tests/Common/Common.cpp

@ -513,3 +513,18 @@ HasProblematicFields HasVirtualReturningHasProblematicFields::returnsProblematic @@ -513,3 +513,18 @@ HasProblematicFields HasVirtualReturningHasProblematicFields::returnsProblematic
{
return HasProblematicFields();
}
int BaseClassVirtual::retInt()
{
return 1;
}
BaseClassVirtual BaseClassVirtual::getBase()
{
return DerivedClassVirtual();
}
int DerivedClassVirtual::retInt()
{
return 2;
}

13
tests/Common/Common.h

@ -821,3 +821,16 @@ public: @@ -821,3 +821,16 @@ public:
HasVirtualReturningHasProblematicFields();
virtual HasProblematicFields returnsProblematicFields();
};
class DLL_API BaseClassVirtual
{
public:
virtual int retInt();
static BaseClassVirtual getBase();
};
class DLL_API DerivedClassVirtual : public BaseClassVirtual
{
public:
virtual int retInt();
};

47
tests/VTables/VTables.Tests.cs

@ -12,6 +12,22 @@ public class FooDerived : Foo @@ -12,6 +12,22 @@ public class FooDerived : Foo
}
}
public class ManagedDerivedClassVirtual : DerivedClassVirtual
{
public override unsafe int RetInt()
{
return 15;
}
}
public class ManagedDerivedClassVirtualRetBase : DerivedClassVirtual
{
public override unsafe int RetInt()
{
return base.RetInt();
}
}
public class VTablesTests : GeneratorTestFixture
{
[Test]
@ -27,7 +43,36 @@ public class VTablesTests : GeneratorTestFixture @@ -27,7 +43,36 @@ public class VTablesTests : GeneratorTestFixture
Assert.That(foo2.CallFoo(), Is.EqualTo(12));
}
static void Main(string[] args)
void TestVirtualFunction(BaseClassVirtual obj, int actual)
{
var ret = obj.RetInt();
Assert.AreEqual(actual, ret);
ret = BaseClassVirtual.VirtualCallRetInt(obj);
Assert.AreEqual(actual, ret);
}
[Test]
public void TestVirtualFuntionRetVal()
{
// Virtual Functions Object Slicing case
// See http://stackoverflow.com/questions/3479712/virtual-functions-object-slicing
var baseVirtual = BaseClassVirtual.GetBase();
TestVirtualFunction(baseVirtual, 5);
BaseClassVirtual baseClass = new DerivedClassVirtual();
TestVirtualFunction(baseClass, 10);
var basePtr = BaseClassVirtual.GetBasePtr();
TestVirtualFunction(basePtr, 10);
var managed = new ManagedDerivedClassVirtual();
TestVirtualFunction(managed, 15);
baseClass = managed;
TestVirtualFunction(baseClass, 15);
var retBase = new ManagedDerivedClassVirtualRetBase();
TestVirtualFunction(retBase, 10);
}
}

26
tests/VTables/VTables.cpp

@ -33,3 +33,29 @@ int FooCallFoo(Foo* foo) @@ -33,3 +33,29 @@ int FooCallFoo(Foo* foo)
{
return foo->vfoo() + 2;
}
int BaseClassVirtual::virtualCallRetInt(BaseClassVirtual* base)
{
return base->retInt();
}
int BaseClassVirtual::retInt()
{
return 5;
}
BaseClassVirtual BaseClassVirtual::getBase()
{
return DerivedClassVirtual();
}
BaseClassVirtual* BaseClassVirtual::getBasePtr()
{
return new DerivedClassVirtual();
}
int DerivedClassVirtual::retInt()
{
return 10;
}

15
tests/VTables/VTables.h

@ -18,3 +18,18 @@ public: @@ -18,3 +18,18 @@ public:
};
DLL_API int FooCallFoo(Foo* foo);
class DLL_API BaseClassVirtual
{
public:
static int virtualCallRetInt(BaseClassVirtual* base);
virtual int retInt();
static BaseClassVirtual getBase();
static BaseClassVirtual* getBasePtr();
};
class DLL_API DerivedClassVirtual : public BaseClassVirtual
{
public:
virtual int retInt() override;
};

Loading…
Cancel
Save