Browse Source

Adjusted pointers when calling functions from secondary or non-dynamic bases.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>
pull/1132/head
Dimitar Dobrev 10 years ago
parent
commit
6f8c942b0a
  1. 12
      src/AST/Class.cs
  2. 25
      src/AST/ClassExtensions.cs
  3. 48
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  4. 105
      src/Generator/Passes/MultipleInheritancePass.cs
  5. 2
      tests/CSharp/CSharp.Tests.cs
  6. 12
      tests/CSharp/CSharp.cpp
  7. 2
      tests/CSharp/CSharp.h

12
src/AST/Class.cs

@ -26,6 +26,18 @@ namespace CppSharp.AST @@ -26,6 +26,18 @@ namespace CppSharp.AST
// Represents a base class of a C++ class.
public class BaseClassSpecifier
{
public BaseClassSpecifier()
{
}
public BaseClassSpecifier(BaseClassSpecifier other)
{
Access = other.Access;
IsVirtual = other.IsVirtual;
Type = other.Type;
Offset = other.Offset;
}
public AccessSpecifier Access { get; set; }
public bool IsVirtual { get; set; }
public Type Type { get; set; }

25
src/AST/ClassExtensions.cs

@ -194,5 +194,30 @@ namespace CppSharp.AST @@ -194,5 +194,30 @@ namespace CppSharp.AST
return hasRefBase;
}
private static bool ComputeClassPath(this Class current, Class target, IList<BaseClassSpecifier> path)
{
if (target == current)
return true;
foreach (var @base in current.Bases)
{
path.Add(@base);
var @class = @base.Class.OriginalClass ?? @base.Class;
if (@class != current && @class.ComputeClassPath(target, path))
return false;
}
path.RemoveAt(path.Count - 1);
return false;
}
public static int ComputeNonVirtualBaseClassOffsetTo(this Class from, Class to)
{
var path = new List<BaseClassSpecifier>();
@from.ComputeClassPath(to, path);
return path.Sum(@base => @base.Offset);
}
}
}

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

@ -42,6 +42,7 @@ namespace CppSharp.Generators.CSharp @@ -42,6 +42,7 @@ namespace CppSharp.Generators.CSharp
public static readonly string InstanceField = Generator.GeneratedIdentifier("instance");
public static readonly string InstanceIdentifier = Generator.GeneratedIdentifier("Instance");
public static readonly string PointerAdjustmentIdentifier = Generator.GeneratedIdentifier("PointerAdjustment");
public static readonly string ReturnIdentifier = Generator.GeneratedIdentifier("ret");
public static readonly string DummyIdentifier = Generator.GeneratedIdentifier("dummy");
public static readonly string TargetIdentifier = Generator.GeneratedIdentifier("target");
@ -396,6 +397,12 @@ namespace CppSharp.Generators.CSharp @@ -396,6 +397,12 @@ namespace CppSharp.Generators.CSharp
WriteLine("public {0} {1} {{ get; protected set; }}",
"global::System.IntPtr", Helpers.InstanceIdentifier);
PopBlock(NewLineKind.BeforeNextBlock);
PushBlock(CSharpBlockKind.Field);
WriteLine("protected int {0};", Helpers.PointerAdjustmentIdentifier);
// use interfaces if any - derived types with a secondary base this class must be compatible with the map
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
WriteLine(
@ -985,13 +992,13 @@ namespace CppSharp.Generators.CSharp @@ -985,13 +992,13 @@ namespace CppSharp.Generators.CSharp
if (type.IsPrimitiveType(out primitiveType))
{
WriteLine("*Internal.{0}({1}, {2}) = value;", internalFunction,
Helpers.InstanceIdentifier, function.Parameters[0].Name);
GetInstanceParam(function), function.Parameters[0].Name);
}
else
{
WriteLine("*({0}.Internal*) Internal.{1}({2}, {3}) = *({0}.Internal*) value.{2};",
type.ToString(), internalFunction,
Helpers.InstanceIdentifier, function.Parameters[0].Name);
WriteLine("*({0}.Internal*) Internal.{1}({2}, {3}) = *({0}.Internal*) value.{4};",
type.ToString(), internalFunction, GetInstanceParam(function),
function.Parameters[0].Name, Helpers.InstanceIdentifier);
}
}
@ -1911,6 +1918,8 @@ namespace CppSharp.Generators.CSharp @@ -1911,6 +1918,8 @@ namespace CppSharp.Generators.CSharp
if (@class.IsRefType)
{
if (@class.HasBaseClass)
WriteLine("{0} = {1};", Helpers.PointerAdjustmentIdentifier, ClassExtensions.ComputeNonVirtualBaseClassOffsetTo(@class, @class.BaseClass));
if (!@class.IsAbstractImpl)
{
WriteLine("if (native == null)");
@ -2548,9 +2557,7 @@ namespace CppSharp.Generators.CSharp @@ -2548,9 +2557,7 @@ namespace CppSharp.Generators.CSharp
}
else
{
names.Insert(instanceIndex, Helpers.InstanceIdentifier);
if (method.SynthKind == FunctionSynthKind.AdjustedMethod)
names[instanceIndex] += " + " + method.AdjustedOffset;
names.Insert(instanceIndex, GetInstanceParam(function));
}
}
}
@ -2622,7 +2629,32 @@ namespace CppSharp.Generators.CSharp @@ -2622,7 +2629,32 @@ namespace CppSharp.Generators.CSharp
WriteCloseBraceIndent();
}
private int GetInstanceParamIndex(Method method)
private static string GetInstanceParam(Function function)
{
var from = (Class) function.Namespace;
var to = function.OriginalFunction == null ? @from.BaseClass :
(Class) function.OriginalFunction.Namespace;
var baseOffset = 0;
if (to != null)
{
to = to.OriginalClass ?? to;
baseOffset = @from.ComputeNonVirtualBaseClassOffsetTo(to);
}
var isPrimaryBase = from.BaseClass == to;
if (isPrimaryBase)
{
return string.Format("({0} + {1}{2})",
Helpers.InstanceIdentifier,
Helpers.PointerAdjustmentIdentifier,
baseOffset == 0 ? string.Empty : (" - " + baseOffset));
}
return string.Format("({0}{1})",
Helpers.InstanceIdentifier,
baseOffset == 0 ? string.Empty : " + " + baseOffset);
}
private int GetInstanceParamIndex(Function method)
{
if (Options.IsMicrosoftAbi)
return 0;

105
src/Generator/Passes/MultipleInheritancePass.cs

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.Generators.CSharp;
@ -37,85 +36,20 @@ namespace CppSharp.Passes @@ -37,85 +36,20 @@ namespace CppSharp.Passes
return result;
}
public static bool ComputeClassPath(Class current, Class target,
List<BaseClassSpecifier> path)
{
if (target == current)
return true;
foreach (var @base in current.Bases)
{
path.Add(@base);
if (ComputeClassPath(@base.Class, target, path))
return false;
}
path.RemoveAt(path.Count-1);
return false;
}
public static List<BaseClassSpecifier> ComputeClassPath(Class from, Class to)
{
var path = new List<BaseClassSpecifier>();
ComputeClassPath(from, to, path);
return path;
}
int ComputeNonVirtualBaseClassOffset(Class from, Class to)
{
var bases = ComputeClassPath(from, to);
return bases.Sum(@base => @base.Offset);
}
public void CheckNonVirtualInheritedFunctions(Class @class, Class originalClass = null)
{
if (originalClass == null)
originalClass = @class;
foreach (BaseClassSpecifier baseSpecifier in @class.Bases)
{
var @base = baseSpecifier.Class;
if (@base.IsInterface) continue;
var nonVirtualOffset = ComputeNonVirtualBaseClassOffset(originalClass, @base);
if (nonVirtualOffset == 0)
continue;
foreach (var method in @base.Methods.Where(method =>
!method.IsVirtual && (method.Kind == CXXMethodKind.Normal)))
{
Console.WriteLine(method);
var adjustedMethod = new Method(method)
{
SynthKind = FunctionSynthKind.AdjustedMethod,
AdjustedOffset = nonVirtualOffset,
};
originalClass.Methods.Add(adjustedMethod);
}
CheckNonVirtualInheritedFunctions(@base, originalClass);
}
}
public override bool VisitClassDecl(Class @class)
{
if (!base.VisitClassDecl(@class))
return false;
//CheckNonVirtualInheritedFunctions(@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].Class;
if (@base.IsInterface) continue;
var @base = @class.Bases[i];
var baseClass = @base.Class;
if (baseClass.IsInterface) continue;
var @interface = GetInterface(@base);
@class.Bases[i] = new BaseClassSpecifier { Type = new TagType(@interface) };
var @interface = GetInterface(baseClass);
@class.Bases[i] = new BaseClassSpecifier(@base) { Type = new TagType(@interface) };
ImplementInterfaceMethods(@class, @interface);
ImplementInterfaceProperties(@class, @interface);
}
@ -148,7 +82,7 @@ namespace CppSharp.Passes @@ -148,7 +82,7 @@ namespace CppSharp.Passes
@interface.Bases.AddRange(
from b in @base.Bases
let i = GetInterface(b.Class)
select new BaseClassSpecifier { Type = new TagType(i) });
select new BaseClassSpecifier(b) { Type = new TagType(i) });
@interface.Methods.AddRange(
from m in @base.Methods
@ -158,7 +92,7 @@ namespace CppSharp.Passes @@ -158,7 +92,7 @@ namespace CppSharp.Passes
@interface.Properties.AddRange(
from property in @base.Properties
where property.IsDeclared
select new Property(property) { Namespace = @interface });
select CreateInterfaceProperty(property, @interface));
@interface.Fields.AddRange(@base.Fields);
// avoid conflicts when potentially renaming later
@ -190,6 +124,26 @@ namespace CppSharp.Passes @@ -190,6 +124,26 @@ namespace CppSharp.Passes
return @interface;
}
private static Property CreateInterfaceProperty(Property property, DeclarationContext @namespace)
{
var interfaceProperty = new Property(property) { Namespace = @namespace };
if (property.GetMethod != null)
interfaceProperty.GetMethod = new Method(property.GetMethod)
{
OriginalFunction = property.GetMethod,
Namespace = @namespace
};
if (property.SetMethod != null)
// handle indexers
interfaceProperty.SetMethod = property.GetMethod == property.SetMethod ?
interfaceProperty.GetMethod : new Method(property.SetMethod)
{
OriginalFunction = property.SetMethod,
Namespace = @namespace
};
return interfaceProperty;
}
private static void ImplementInterfaceMethods(Class @class, Class @interface)
{
var parameterTypeComparer = new ParameterTypeComparer();
@ -218,7 +172,8 @@ namespace CppSharp.Passes @@ -218,7 +172,8 @@ namespace CppSharp.Passes
{
foreach (var property in @interface.Properties.Where(p => p.Name != Helpers.InstanceIdentifier))
{
var impl = new Property(property) { Namespace = @class, OriginalNamespace = @interface };
var impl = CreateInterfaceProperty(property, @class);
impl.OriginalNamespace = @interface;
var rootBaseProperty = @class.GetBaseProperty(property, true);
if (rootBaseProperty != null && rootBaseProperty.IsDeclared)
impl.ExplicitInterfaceImpl = @interface;

2
tests/CSharp/CSharp.Tests.cs

@ -258,7 +258,7 @@ public class CSharpTests : GeneratorTestFixture @@ -258,7 +258,7 @@ public class CSharpTests : GeneratorTestFixture
Assert.AreEqual(5, Foo.Rename);
}
[Test, Ignore]
[Test]
public void TestPrimarySecondaryBase()
{
var a = new MI_A0();

12
tests/CSharp/CSharp.cpp

@ -83,12 +83,18 @@ QColor::QColor(Qt::GlobalColor color) @@ -83,12 +83,18 @@ QColor::QColor(Qt::GlobalColor color)
Qux::Qux()
{
}
Qux::Qux(const Qux& other)
{
for (int i = 0; i < 3; i++)
{
array[i] = other.array[i];
}
}
Qux::Qux(Foo foo)
{
}
Qux::Qux(Bar bar)
@ -114,6 +120,10 @@ void Qux::setInterface(Qux *qux) @@ -114,6 +120,10 @@ void Qux::setInterface(Qux *qux)
{
}
void Qux::v()
{
}
Bar::Bar(Qux qux)
{
}

2
tests/CSharp/CSharp.h

@ -39,6 +39,7 @@ class DLL_API Qux @@ -39,6 +39,7 @@ class DLL_API Qux
{
public:
Qux();
Qux(const Qux& other);
Qux(Foo foo);
Qux(Bar bar);
int farAwayFunc() const;
@ -46,6 +47,7 @@ public: @@ -46,6 +47,7 @@ public:
void obsolete();
Qux* getInterface();
void setInterface(Qux* qux);
virtual void v();
};
class DLL_API Bar : public Qux

Loading…
Cancel
Save