Browse Source

Merge pull request #68 from ddobrev/multiple_inheritance

Multiple inheritance
pull/69/head
João Matos 12 years ago
parent
commit
679c1760f4
  1. 33
      src/AST/Class.cs
  2. 2
      src/AST/Method.cs
  3. 16
      src/AST/Property.cs
  4. 6
      src/Generator/Driver.cs
  5. 7
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  6. 117
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  7. 11
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  8. 11
      src/Generator/Passes/CheckDuplicatedNamesPass.cs
  9. 4
      src/Generator/Passes/GenerateAbstractImplementationsPass.cs
  10. 129
      src/Generator/Passes/MultipleInheritancePass.cs
  11. 49
      src/Generator/Passes/ParamTypeToInterfacePass.cs
  12. 15
      tests/CSharpTemp/CSharpTemp.Tests.cs
  13. 25
      tests/CSharpTemp/CSharpTemp.cpp
  14. 5
      tests/CSharpTemp/CSharpTemp.cs
  15. 17
      tests/CSharpTemp/CSharpTemp.h

33
src/AST/Class.cs

@ -59,6 +59,7 @@ namespace CppSharp.AST @@ -59,6 +59,7 @@ namespace CppSharp.AST
{
ValueType,
RefType,
Interface
}
// Represents a C++ record Decl.
@ -139,6 +140,8 @@ namespace CppSharp.AST @@ -139,6 +140,8 @@ namespace CppSharp.AST
}
}
public Class OriginalClass { get; set; }
public bool IsValueType
{
get { return Type == ClassType.ValueType || IsUnion; }
@ -149,6 +152,11 @@ namespace CppSharp.AST @@ -149,6 +152,11 @@ namespace CppSharp.AST
get { return Type == ClassType.RefType && !IsUnion; }
}
public bool IsInterface
{
get { return Type == ClassType.Interface; }
}
public IEnumerable<Method> Constructors
{
get
@ -201,9 +209,10 @@ namespace CppSharp.AST @@ -201,9 +209,10 @@ namespace CppSharp.AST
}
}
public Method GetRootBaseMethod(Method @override)
public Method GetRootBaseMethod(Method @override, bool onlyFirstBase = false)
{
return (from @base in Bases
where !onlyFirstBase || !@base.Class.IsInterface
let baseMethod = (
from method in @base.Class.Methods
where
@ -213,8 +222,26 @@ namespace CppSharp.AST @@ -213,8 +222,26 @@ namespace CppSharp.AST
method.Parameters.SequenceEqual(@override.Parameters,
new ParameterTypeComparer())
select method).FirstOrDefault()
let rootBaseMethod = @base.Class.GetRootBaseMethod(@override)
select rootBaseMethod ?? baseMethod).FirstOrDefault();
let rootBaseMethod = @base.Class.GetRootBaseMethod(@override) ?? baseMethod
where rootBaseMethod != null || onlyFirstBase
select rootBaseMethod).FirstOrDefault();
}
public Property GetRootBaseProperty(Property @override, bool onlyFirstBase = false)
{
return (from @base in Bases
where !onlyFirstBase || !@base.Class.IsInterface
let baseProperty = (
from property in @base.Class.Properties
where
property.Name == @override.Name &&
property.Parameters.Count == @override.Parameters.Count &&
property.Parameters.SequenceEqual(@override.Parameters,
new ParameterTypeComparer())
select property).FirstOrDefault()
let rootBaseProperty = @base.Class.GetRootBaseProperty(@override) ?? baseProperty
where rootBaseProperty != null || onlyFirstBase
select rootBaseProperty).FirstOrDefault();
}
public override T Visit<T>(IDeclVisitor<T> visitor)

2
src/AST/Method.cs

@ -126,6 +126,8 @@ namespace CppSharp.AST @@ -126,6 +126,8 @@ namespace CppSharp.AST
public MethodConversionKind Conversion { get; set; }
public Class ExplicitInterfaceImpl { get; set; }
public override QualifiedType GetFunctionType()
{
var qualifiedType = base.GetFunctionType();

16
src/AST/Property.cs

@ -7,6 +7,20 @@ namespace CppSharp.AST @@ -7,6 +7,20 @@ namespace CppSharp.AST
/// </summary>
public class Property : Declaration, ITypedDecl
{
public Property()
{
}
public Property(Property property)
: base(property)
{
QualifiedType = property.QualifiedType;
GetMethod = property.GetMethod;
SetMethod = property.SetMethod;
Field = property.Field;
parameters.AddRange(property.Parameters);
}
public Type Type
{
get { return QualifiedType.Type; }
@ -38,6 +52,8 @@ namespace CppSharp.AST @@ -38,6 +52,8 @@ namespace CppSharp.AST
// The field that should be get and set by this property
public Field Field { get; set; }
public Class ExplicitInterfaceImpl { get; set; }
private readonly List<Parameter> parameters = new List<Parameter>();
/// <summary>

6
src/Generator/Driver.cs

@ -153,6 +153,11 @@ namespace CppSharp @@ -153,6 +153,11 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new CheckDuplicatedNamesPass());
if (Options.GenerateAbstractImpls)
TranslationUnitPasses.AddPass(new GenerateAbstractImplementationsPass());
if (Options.GenerateInterfacesForMultipleInheritance)
{
TranslationUnitPasses.AddPass(new MultipleInheritancePass());
TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass());
}
}
public void ProcessCode()
@ -271,6 +276,7 @@ namespace CppSharp @@ -271,6 +276,7 @@ namespace CppSharp
public bool GeneratePartialClasses;
public bool GenerateVirtualTables;
public bool GenerateAbstractImpls;
public bool GenerateInterfacesForMultipleInheritance;
public bool GenerateInternalImports;
public string IncludePrefix;
public bool WriteOnlyWhenChanged;

7
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -277,7 +277,7 @@ namespace CppSharp.Generators.CSharp @@ -277,7 +277,7 @@ namespace CppSharp.Generators.CSharp
}
Context.Return.Write("new {0}({1})",
QualifiedIdentifier(@class) +
QualifiedIdentifier(@class.OriginalClass ?? @class) +
(Context.Driver.Options.GenerateAbstractImpls && @class.IsAbstract ?
"Internal" : ""),
instance);
@ -541,9 +541,10 @@ namespace CppSharp.Generators.CSharp @@ -541,9 +541,10 @@ namespace CppSharp.Generators.CSharp
return;
}
Context.Return.Write("*({0}.Internal*){1}.{2}", CSharpMarshalNativeToManagedPrinter.QualifiedIdentifier(@class),
var qualifiedIdentifier = CSharpMarshalNativeToManagedPrinter.QualifiedIdentifier(
@class.OriginalClass ?? @class);
Context.Return.Write("*({0}.Internal*){1}.{2}", qualifiedIdentifier,
Helpers.SafeIdentifier(Context.Parameter.Name), Helpers.InstanceIdentifier);
}
private void MarshalValueClass(Class @class)

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

@ -30,8 +30,7 @@ namespace CppSharp.Generators.CSharp @@ -30,8 +30,7 @@ namespace CppSharp.Generators.CSharp
public static string SafeIdentifier(string id)
{
id = new string(((IEnumerable<char>)id)
.Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
id = new string(id.Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
return Keywords.Contains(id) ? "@" + id : id;
}
@ -59,9 +58,9 @@ namespace CppSharp.Generators.CSharp @@ -59,9 +58,9 @@ namespace CppSharp.Generators.CSharp
get { return Generator.GeneratedIdentifier("Instance"); }
}
public static string GetAccess(Class @class)
public static string GetAccess(AccessSpecifier accessSpecifier)
{
switch (@class.Access)
switch (accessSpecifier)
{
case AccessSpecifier.Private:
return "internal ";
@ -93,6 +92,7 @@ namespace CppSharp.Generators.CSharp @@ -93,6 +92,7 @@ namespace CppSharp.Generators.CSharp
public const int Field = FIRST + 14;
public const int VTableDelegate = FIRST + 16;
public const int Region = FIRST + 17;
public const int Interface = FIRST + 18;
}
public class CSharpTextTemplate : Template
@ -220,7 +220,10 @@ namespace CppSharp.Generators.CSharp @@ -220,7 +220,10 @@ namespace CppSharp.Generators.CSharp
if (@class.IsDependent)
continue;
GenerateClass(@class);
if (@class.IsInterface)
GenerateInterface(@class);
else
GenerateClass(@class);
}
if (context.HasFunctions)
@ -356,6 +359,57 @@ namespace CppSharp.Generators.CSharp @@ -356,6 +359,57 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateInterface(Class @class)
{
if (@class.Ignore || @class.IsIncomplete)
return;
PushBlock(CSharpBlockKind.Interface);
GenerateDeclarationCommon(@class);
GenerateClassProlog(@class);
NewLine();
WriteStartBraceIndent();
GenerateDeclContext(@class);
foreach (var method in @class.Methods.Where(m => !ASTUtils.CheckIgnoreMethod(m) &&
m.Access == AccessSpecifier.Public))
{
PushBlock(CSharpBlockKind.Method);
GenerateDeclarationCommon(method);
var functionName = GetFunctionIdentifier(method);
Write("{0} {1}(", method.OriginalReturnType, functionName);
Write(FormatMethodParameters(method.Parameters));
WriteLine(");");
PopBlock(NewLineKind.BeforeNextBlock);
}
foreach (var prop in @class.Properties.Where(p => !p.Ignore))
{
PushBlock(CSharpBlockKind.Property);
var type = prop.Type;
if (prop.Parameters.Count > 0 && prop.Type.IsPointerToPrimitiveType())
type = ((PointerType) prop.Type).Pointee;
Write("{0} {1} {{ ", type, GetPropertyName(prop));
if (prop.HasGetter)
Write("get; ");
if (prop.HasSetter)
Write("set; ");
WriteLine("}");
PopBlock(NewLineKind.BeforeNextBlock);
}
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateValueClassFields(Class @class)
{
GenerateClassFields(@class, field =>
@ -609,8 +663,7 @@ namespace CppSharp.Generators.CSharp @@ -609,8 +663,7 @@ namespace CppSharp.Generators.CSharp
if (@class.HasBaseClass)
baseClass = @class.Bases[0].Class;
var hasRefBase = baseClass != null && baseClass.IsRefType
&& !baseClass.Ignore;
var hasRefBase = baseClass != null && baseClass.IsRefType && !baseClass.Ignore;
var hasIgnoredBase = baseClass != null && baseClass.Ignore;
@ -622,7 +675,7 @@ namespace CppSharp.Generators.CSharp @@ -622,7 +675,7 @@ namespace CppSharp.Generators.CSharp
if (@class.IsUnion)
WriteLine("[StructLayout(LayoutKind.Explicit)]");
Write(Helpers.GetAccess(@class));
Write(Helpers.GetAccess(@class.Access));
Write("unsafe ");
if (Driver.Options.GenerateAbstractImpls && @class.IsAbstract)
@ -631,7 +684,7 @@ namespace CppSharp.Generators.CSharp @@ -631,7 +684,7 @@ namespace CppSharp.Generators.CSharp
if (Options.GeneratePartialClasses)
Write("partial ");
Write(@class.IsValueType ? "struct " : "class ");
Write(@class.IsInterface ? "interface " : (@class.IsValueType ? "struct " : "class "));
Write("{0}", SafeIdentifier(@class.Name));
var needsBase = @class.HasBaseClass && !@class.IsValueType
@ -643,8 +696,9 @@ namespace CppSharp.Generators.CSharp @@ -643,8 +696,9 @@ namespace CppSharp.Generators.CSharp
if (needsBase)
{
var qualifiedBase = QualifiedIdentifier(@class.Bases[0].Class);
Write("{0}", qualifiedBase);
Write("{0}", string.Join(", ",
from @base in @class.Bases
select QualifiedIdentifier(@base.Class)));
if (@class.IsRefType)
Write(", ");
@ -792,16 +846,17 @@ namespace CppSharp.Generators.CSharp @@ -792,16 +846,17 @@ namespace CppSharp.Generators.CSharp
Type type;
returnType.Type.IsPointerTo(out type);
PrimitiveType primitiveType;
string internalFunction = GetFunctionNativeIdentifier(function);
if (type.IsPrimitiveType(out primitiveType))
{
string internalFunction = GetFunctionNativeIdentifier(function);
WriteLine("*Internal.{0}({1}, {2}) = value;", internalFunction,
Helpers.InstanceIdentifier, function.Parameters[0].Name);
}
else
{
WriteLine("*({0}.Internal*) this[{1}].{2} = *({0}.Internal*) value.{2};",
type.ToString(), function.Parameters[0].Name, Helpers.InstanceIdentifier);
WriteLine("*({0}.Internal*) Internal.{1}({2}, {3}) = *({0}.Internal*) value.{2};",
type.ToString(), internalFunction,
Helpers.InstanceIdentifier, function.Parameters[0].Name);
}
}
@ -929,11 +984,15 @@ namespace CppSharp.Generators.CSharp @@ -929,11 +984,15 @@ namespace CppSharp.Generators.CSharp
{
PushBlock(CSharpBlockKind.Property);
var type = prop.Type;
// if it's an indexer that returns an address use the real type because there is a setter anyway
if (prop.Parameters.Count > 0 && prop.Type.IsPointerToPrimitiveType())
type = ((PointerType) prop.Type).Pointee;
WriteLine("{0} {1} {2}",
prop.Access == AccessSpecifier.Public ? "public" : "protected",
type, GetPropertyName(prop));
if (prop.ExplicitInterfaceImpl == null)
WriteLine("{0}{1} {2}", Helpers.GetAccess(prop.Access),
type, GetPropertyName(prop));
else
WriteLine("{0} {1}.{2}", type, prop.ExplicitInterfaceImpl.Name, GetPropertyName(prop));
WriteStartBraceIndent();
if (prop.Field != null)
@ -1523,14 +1582,9 @@ namespace CppSharp.Generators.CSharp @@ -1523,14 +1582,9 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.Method);
GenerateDeclarationCommon(method);
switch (GetValidMethodAccess(method, @class))
if (method.ExplicitInterfaceImpl == null)
{
case AccessSpecifier.Public:
Write("public ");
break;
case AccessSpecifier.Protected:
Write("protected ");
break;
Write(Helpers.GetAccess(GetValidMethodAccess(method)));
}
if (method.IsVirtual && !method.IsOverride &&
@ -1553,8 +1607,11 @@ namespace CppSharp.Generators.CSharp @@ -1553,8 +1607,11 @@ namespace CppSharp.Generators.CSharp
if (method.IsConstructor || method.IsDestructor)
Write("{0}(", functionName);
else
else if (method.ExplicitInterfaceImpl == null)
Write("{0} {1}(", method.OriginalReturnType, functionName);
else
Write("{0} {1}.{2}(", method.OriginalReturnType,
method.ExplicitInterfaceImpl.Name, functionName);
Write(FormatMethodParameters(method.Parameters));
@ -1617,7 +1674,7 @@ namespace CppSharp.Generators.CSharp @@ -1617,7 +1674,7 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
}
private static AccessSpecifier GetValidMethodAccess(Method method, Class @class)
private static AccessSpecifier GetValidMethodAccess(Method method)
{
switch (method.Access)
{
@ -1625,7 +1682,7 @@ namespace CppSharp.Generators.CSharp @@ -1625,7 +1682,7 @@ namespace CppSharp.Generators.CSharp
return AccessSpecifier.Public;
default:
return method.IsOverride ?
@class.GetRootBaseMethod(method).Access : method.Access;
((Class) method.Namespace).GetRootBaseMethod(method).Access : method.Access;
}
}
@ -1985,7 +2042,7 @@ namespace CppSharp.Generators.CSharp @@ -1985,7 +2042,7 @@ namespace CppSharp.Generators.CSharp
return string.Join(", ",
from param in @params
where param.Kind != ParameterKind.IndirectReturnType
let typeName = param.CSharpType(this.TypePrinter)
let typeName = param.CSharpType(TypePrinter)
select string.Format("{0}{1} {2}", GetParameterUsage(param.Usage),
typeName, SafeIdentifier(param.Name)));
}
@ -2015,8 +2072,8 @@ namespace CppSharp.Generators.CSharp @@ -2015,8 +2072,8 @@ namespace CppSharp.Generators.CSharp
WriteLine("[UnmanagedFunctionPointerAttribute(CallingConvention.{0})]",
Helpers.ToCSharpCallConv(functionType.CallingConvention));
TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
WriteLine("{0} unsafe {1};",
typedef.Access == AccessSpecifier.Public ? "public" : "protected",
WriteLine("{0}unsafe {1};",
Helpers.GetAccess(typedef.Access),
string.Format(TypePrinter.VisitDelegate(functionType).Type,
SafeIdentifier(typedef.Name)));
TypePrinter.PopContext();

11
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -349,12 +349,11 @@ namespace CppSharp.Generators.CSharp @@ -349,12 +349,11 @@ namespace CppSharp.Generators.CSharp
public CSharpTypePrinterResult VisitClassDecl(Class @class)
{
var nestedName = GetNestedQualifiedName(@class);
if (ContextKind == CSharpTypePrinterContextKind.Native)
return string.Format("{0}.Internal", nestedName);
return nestedName;
if (ContextKind == CSharpTypePrinterContextKind.Native)
return string.Format("{0}.Internal",
GetNestedQualifiedName(@class.OriginalClass ?? @class));
return GetNestedQualifiedName(@class);
}
public CSharpTypePrinterResult VisitFieldDecl(Field field)

11
src/Generator/Passes/CheckDuplicatedNamesPass.cs

@ -31,6 +31,13 @@ namespace CppSharp.Passes @@ -31,6 +31,13 @@ namespace CppSharp.Passes
return UpdateName(method);
}
var property = decl as Property;
var isIndexer = property != null && property.Parameters.Count > 0;
if (isIndexer)
{
return false;
}
var count = Count++;
if (count == 0)
return false;
@ -93,7 +100,7 @@ namespace CppSharp.Passes @@ -93,7 +100,7 @@ namespace CppSharp.Passes
public override bool VisitProperty(Property decl)
{
if(!AlreadyVisited(decl))
if(!AlreadyVisited(decl) && decl.ExplicitInterfaceImpl == null)
CheckDuplicate(decl);
return false;
@ -104,7 +111,7 @@ namespace CppSharp.Passes @@ -104,7 +111,7 @@ namespace CppSharp.Passes
if (ASTUtils.CheckIgnoreMethod(decl))
return false;
if(!AlreadyVisited(decl))
if (!AlreadyVisited(decl) && decl.ExplicitInterfaceImpl == null)
CheckDuplicate(decl);
return false;

4
src/Generator/Passes/GenerateAbstractImplementationsPass.cs

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.Utils;
namespace CppSharp.Passes
{
@ -52,7 +51,8 @@ namespace CppSharp.Passes @@ -52,7 +51,8 @@ namespace CppSharp.Passes
foreach (var abstractMethod in abstractMethods)
{
internalImpl.Methods.Add(new Method(abstractMethod));
var method = new Method(abstractMethod) { Namespace = internalImpl };
internalImpl.Methods.Add(method);
var @delegate = new TypedefDecl
{
Name = abstractMethod.Name + "Delegate",

129
src/Generator/Passes/MultipleInheritancePass.cs

@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.Generators.CSharp;
namespace CppSharp.Passes
{
public class MultipleInheritancePass : TranslationUnitPass
{
/// <summary>
/// Collects all interfaces in a unit to be added at the end
/// because the unit cannot be changed while it's being iterated though.
/// We also need it to check if a class already has a complementary interface
/// because different classes may have the same secondary bases.
/// </summary>
private readonly Dictionary<Class, Class> interfaces = new Dictionary<Class, Class>();
public override bool VisitTranslationUnit(TranslationUnit unit)
{
bool result = base.VisitTranslationUnit(unit);
foreach (var @interface in interfaces)
@interface.Key.Namespace.Classes.Add(@interface.Value);
interfaces.Clear();
return result;
}
public override bool VisitClassDecl(Class @class)
{
// skip the first base because we can inherit from one class
for (int i = 1; i < @class.Bases.Count; i++)
{
var @base = @class.Bases[i].Class;
if (@base.IsInterface) continue;
var @interface = GetInterface(@class, @base, true);
@class.Bases[i] = new BaseClassSpecifier { Type = new TagType(@interface) };
}
return base.VisitClassDecl(@class);
}
private Class GetInterface(Class @class, Class @base, bool addMembers = false)
{
if (@base.CompleteDeclaration != null)
@base = (Class) @base.CompleteDeclaration;
var name = "I" + @base.Name;
if (interfaces.ContainsKey(@base))
return interfaces[@base];
return @base.Namespace.Classes.FirstOrDefault(c => c.Name == name) ??
GetNewInterface(@class, name, @base, addMembers);
}
private Class GetNewInterface(Class @class, string name, Class @base, bool addMembers = false)
{
var @interface = new Class
{
Name = name,
Namespace = @base.Namespace,
Access = @base.Access,
Type = ClassType.Interface,
OriginalClass = @base
};
@interface.Bases.AddRange(
from b in @base.Bases
let i = GetInterface(@base, b.Class)
select new BaseClassSpecifier { Type = new TagType(i) });
@interface.Methods.AddRange(@base.Methods.Where(
m => !m.IsConstructor && !m.IsDestructor && !m.IsStatic && !m.Ignore));
@interface.Properties.AddRange(@base.Properties.Where(p => !p.Ignore));
if (@interface.Bases.Count == 0)
{
Property instance = new Property();
instance.Name = Helpers.InstanceIdentifier;
instance.QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr));
instance.GetMethod = new Method();
@interface.Properties.Add(instance);
}
@interface.Events.AddRange(@base.Events);
if (addMembers)
{
ImplementInterfaceMethods(@class, @interface);
ImplementInterfaceProperties(@class, @interface);
}
if (@base.Bases.All(b => b.Class != @interface))
@base.Bases.Add(new BaseClassSpecifier { Type = new TagType(@interface) });
interfaces.Add(@base, @interface);
return @interface;
}
private static void ImplementInterfaceMethods(Class @class, Class @interface)
{
foreach (var method in @interface.Methods)
{
var impl = new Method(method)
{
Namespace = @class,
IsVirtual = false,
IsOverride = false
};
var rootBaseMethod = @class.GetRootBaseMethod(method, true);
if (rootBaseMethod != null && !rootBaseMethod.Ignore)
impl.ExplicitInterfaceImpl = @interface;
@class.Methods.Add(impl);
}
foreach (var @base in @interface.Bases)
ImplementInterfaceMethods(@class, @base.Class);
}
private static void ImplementInterfaceProperties(Class @class, Class @interface)
{
foreach (var property in @interface.Properties.Where(p => p.Name != Helpers.InstanceIdentifier))
{
var impl = new Property(property) { Namespace = @class };
var rootBaseProperty = @class.GetRootBaseProperty(property, true);
if (rootBaseProperty != null && !rootBaseProperty.Ignore)
impl.ExplicitInterfaceImpl = @interface;
@class.Properties.Add(impl);
}
foreach (var @base in @interface.Bases)
ImplementInterfaceProperties(@class, @base.Class);
}
}
}

49
src/Generator/Passes/ParamTypeToInterfacePass.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
using CppSharp.AST;
namespace CppSharp.Passes
{
public class ParamTypeToInterfacePass : TranslationUnitPass
{
public override bool VisitFunctionDecl(Function function)
{
if (function.HasIndirectReturnTypeParameter)
{
var parameter = function.Parameters.Find(p => p.Kind == ParameterKind.IndirectReturnType);
parameter.QualifiedType = GetInterfaceType(parameter.QualifiedType);
}
else
{
function.ReturnType = GetInterfaceType(function.ReturnType);
}
return base.VisitFunctionDecl(function);
}
public override bool VisitParameterDecl(Parameter parameter)
{
parameter.QualifiedType = GetInterfaceType(parameter.QualifiedType);
return base.VisitParameterDecl(parameter);
}
private static QualifiedType GetInterfaceType(QualifiedType type)
{
var tagType = type.Type as TagType;
if (tagType == null)
{
var pointerType = type.Type as PointerType;
if (pointerType != null)
tagType = pointerType.Pointee as TagType;
}
if (tagType != null)
{
var @class = tagType.Declaration as Class;
if (@class != null)
{
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
if (@interface != null)
return new QualifiedType(new TagType(@interface));
}
}
return type;
}
}
}

15
tests/CSharpTemp/CSharpTemp.Tests.cs

@ -30,4 +30,19 @@ public class CSharpTempTests @@ -30,4 +30,19 @@ public class CSharpTempTests
Assert.That(typeof(Foo).GetProperty("P",
BindingFlags.Instance | BindingFlags.NonPublic), Is.Not.Null);
}
[Test]
public void TestMultipleInheritance()
{
Baz baz = new Baz();
Assert.That(baz.method(), Is.EqualTo(1));
var bar = (IBar) baz;
Assert.That(bar.method(), Is.EqualTo(2));
Assert.That(baz[0], Is.EqualTo(50));
bar[0] = new Foo { A = 1000 };
Assert.That(bar[0].A, Is.EqualTo(1000));
Assert.That(baz.farAwayFunc(), Is.EqualTo(20));
Assert.That(baz.takesQux(baz), Is.EqualTo(20));
Assert.That(baz.returnQux().farAwayFunc(), Is.EqualTo(20));
}
}

25
tests/CSharpTemp/CSharpTemp.cpp

@ -6,6 +6,11 @@ Foo::Foo() @@ -6,6 +6,11 @@ Foo::Foo()
P = 50;
}
int Foo::method()
{
return 1;
}
int Foo::operator[](int i) const
{
return 5;
@ -26,7 +31,27 @@ const Foo& Bar::operator[](int i) const @@ -26,7 +31,27 @@ const Foo& Bar::operator[](int i) const
return m_foo;
}
int Qux::farAwayFunc() const
{
return 20;
}
int Bar::method()
{
return 2;
}
Foo& Bar::operator[](int i)
{
return m_foo;
}
int Baz::takesQux(const Qux& qux)
{
return qux.farAwayFunc();
}
Qux Baz::returnQux()
{
return Qux();
}

5
tests/CSharpTemp/CSharpTemp.cs

@ -10,6 +10,11 @@ namespace CppSharp.Tests @@ -10,6 +10,11 @@ namespace CppSharp.Tests
{
}
public override void SetupPasses(Driver driver)
{
driver.Options.GenerateInterfacesForMultipleInheritance = true;
}
static class Program
{
public static void Main(string[] args)

17
tests/CSharpTemp/CSharpTemp.h

@ -8,6 +8,7 @@ class DLL_API Foo @@ -8,6 +8,7 @@ class DLL_API Foo
{
public:
Foo();
int method();
int operator[](int i) const;
int operator[](unsigned int i);
int& operator[](int i);
@ -17,12 +18,26 @@ protected: @@ -17,12 +18,26 @@ protected:
int P;
};
class DLL_API Bar
class DLL_API Qux
{
public:
int farAwayFunc() const;
};
class DLL_API Bar : public Qux
{
public:
int method();
const Foo& operator[](int i) const;
Foo& operator[](int i);
private:
Foo m_foo;
};
class DLL_API Baz : public Foo, public Bar
{
public:
int takesQux(const Qux& qux);
Qux returnQux();
};

Loading…
Cancel
Save