Browse Source

Completed the support for multiple inheritance with the exception of base interfaces and the cast operator in the derived class to the second or later base.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>
pull/68/head
Dimitar Dobrev 12 years ago
parent
commit
f5304e69bb
  1. 2
      src/AST/Class.cs
  2. 24
      src/AST/Property.cs
  3. 116
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  4. 53
      src/Generator/Passes/MultipleInheritancePass.cs
  5. 8
      tests/CSharpTemp/CSharpTemp.Tests.cs
  6. 10
      tests/CSharpTemp/CSharpTemp.cpp
  7. 7
      tests/CSharpTemp/CSharpTemp.h

2
src/AST/Class.cs

@ -82,6 +82,8 @@ namespace CppSharp.AST @@ -82,6 +82,8 @@ namespace CppSharp.AST
// True if class provides pure virtual methods.
public bool IsAbstract;
public bool IsInterface { get; set; }
// True if the type is to be treated as a union.
public bool IsUnion;

24
src/AST/Property.cs

@ -7,6 +7,30 @@ namespace CppSharp.AST @@ -7,6 +7,30 @@ namespace CppSharp.AST
/// </summary>
public class Property : Declaration, ITypedDecl
{
public Property()
{
}
public Property(Property property)
: base(property)
{
QualifiedType = property.QualifiedType;
if (property.GetMethod != null)
GetMethod = new Method(property.GetMethod);
if (property.GetMethod == property.SetMethod)
{
SetMethod = GetMethod;
}
else
{
if (property.SetMethod != null)
SetMethod = new Method(property.SetMethod);
}
if (property.Field != null)
Field = property.Field;
parameters.AddRange(property.Parameters);
}
public Type Type
{
get { return QualifiedType.Type; }

116
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;
}
@ -220,7 +219,10 @@ namespace CppSharp.Generators.CSharp @@ -220,7 +219,10 @@ namespace CppSharp.Generators.CSharp
if (@class.IsDependent)
continue;
GenerateClass(@class);
if (@class.IsInterface)
GenerateInterface(@class);
else
GenerateClass(@class);
}
if (context.HasFunctions)
@ -356,6 +358,80 @@ namespace CppSharp.Generators.CSharp @@ -356,6 +358,80 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateInterface(Class @class)
{
if (@class.Ignore || @class.IsIncomplete)
return;
PushBlock(CSharpBlockKind.Class);
GenerateDeclarationCommon(@class);
Write(Helpers.GetAccess(@class));
Write("unsafe ");
if (Options.GeneratePartialClasses)
Write("partial ");
Write("interface ");
Write("{0}", SafeIdentifier(@class.Name));
//var needsBase = @class.HasBaseClass && !@class.IsValueType
// && !@class.Bases[0].Class.IsValueType
// && !@class.Bases[0].Class.Ignore;
//if (needsBase || @class.IsRefType)
// Write(" : ");
//if (needsBase)
//{
// var qualifiedBase = QualifiedIdentifier(@class.Bases[0].Class);
// Write("{0}", qualifiedBase);
// if (@class.IsRefType)
// Write(", ");
//}
NewLine();
WriteStartBraceIndent();
GenerateDeclContext(@class);
foreach (var method in @class.Methods.Where(m => !ASTUtils.CheckIgnoreMethod(m)))
{
PushBlock(CSharpBlockKind.Method);
GenerateDeclarationCommon(method);
var functionName = GetFunctionIdentifier(method);
Write("{0} {1}(", method.OriginalReturnType, functionName);
Write(FormatMethodParameters(method.Parameters));
Write(");");
NewLine();
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 =>
@ -610,7 +686,7 @@ namespace CppSharp.Generators.CSharp @@ -610,7 +686,7 @@ namespace CppSharp.Generators.CSharp
baseClass = @class.Bases[0].Class;
var hasRefBase = baseClass != null && baseClass.IsRefType
&& !baseClass.Ignore;
&& !baseClass.Ignore && !baseClass.IsInterface;
var hasIgnoredBase = baseClass != null && baseClass.Ignore;
@ -643,8 +719,9 @@ namespace CppSharp.Generators.CSharp @@ -643,8 +719,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(", ");
@ -1360,7 +1437,8 @@ namespace CppSharp.Generators.CSharp @@ -1360,7 +1437,8 @@ namespace CppSharp.Generators.CSharp
private void GenerateDisposeMethods(Class @class)
{
var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType;
var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType &&
!@class.BaseClass.IsInterface;
// Generate the IDispose Dispose() method.
if (!hasBaseClass)
@ -1429,7 +1507,8 @@ namespace CppSharp.Generators.CSharp @@ -1429,7 +1507,8 @@ namespace CppSharp.Generators.CSharp
WriteLine("internal {0}(global::System.IntPtr native){1}", safeIdentifier,
@class.IsValueType ? " : this()" : string.Empty);
var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType;
var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType &&
!@class.BaseClass.IsInterface;
if (hasBaseClass)
WriteLineIndent(": base(native)");
@ -1523,14 +1602,18 @@ namespace CppSharp.Generators.CSharp @@ -1523,14 +1602,18 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.Method);
GenerateDeclarationCommon(method);
switch (GetValidMethodAccess(method, @class))
// check if this is an explicit interface implementation
if (!method.Name.Contains('.'))
{
case AccessSpecifier.Public:
Write("public ");
break;
case AccessSpecifier.Protected:
Write("protected ");
break;
switch (GetValidMethodAccess(method, @class))
{
case AccessSpecifier.Public:
Write("public ");
break;
case AccessSpecifier.Protected:
Write("protected ");
break;
}
}
if (method.IsVirtual && !method.IsOverride &&
@ -1549,7 +1632,8 @@ namespace CppSharp.Generators.CSharp @@ -1549,7 +1632,8 @@ namespace CppSharp.Generators.CSharp
if (Driver.Options.GenerateAbstractImpls && method.IsPure)
Write("abstract ");
var functionName = GetFunctionIdentifier(method);
var functionName = method.IsOperator ?
Operators.GetOperatorIdentifier(method.OperatorKind) : method.Name;
if (method.IsConstructor || method.IsDestructor)
Write("{0}(", functionName);

53
src/Generator/Passes/MultipleInheritancePass.cs

@ -25,18 +25,53 @@ namespace CppSharp.Passes @@ -25,18 +25,53 @@ namespace CppSharp.Passes
for (int i = 1; i < @class.Bases.Count; i++)
{
var @base = @class.Bases[i].Class;
if (@base.IsInterface) continue;
if (@base.CompleteDeclaration != null)
@base = (Class) @base.CompleteDeclaration;
var name = "I" + @base.Name;
if (!interfaces.ContainsKey(@base) && @base.Namespace.Classes.All(c => c.Name != name))
{
Class @interface = new Class { Name = name, Namespace = @class.Namespace };
@interface.IsAbstract = true;
@interface.Methods.AddRange(@class.Methods);
@interface.Properties.AddRange(@class.Properties);
@interface.Events.AddRange(@class.Events);
@interfaces.Add(@class, @interface);
}
var @interface = (interfaces.ContainsKey(@base)
? interfaces[@base]
: @base.Namespace.Classes.FirstOrDefault(c => c.Name == name)) ??
GetNewInterface(@class, name, @base);
@class.Bases[i] = new BaseClassSpecifier { Type = new TagType(@interface) };
}
return base.VisitClassDecl(@class);
}
private Class GetNewInterface(Class @class, string name, Class @base)
{
var @interface = new Class
{
Name = name,
Namespace = @base.Namespace,
Access = @base.Access,
IsInterface = true
};
@interface.Methods.AddRange(@base.Methods.Where(
m => !m.IsConstructor && !m.IsDestructor && !m.IsStatic && !m.Ignore));
foreach (var method in @interface.Methods)
{
var impl = new Method(method)
{
Namespace = @class,
IsVirtual = false,
IsOverride = false
};
var rootBaseMethod = @class.GetRootBaseMethod(method);
if (rootBaseMethod != null && !rootBaseMethod.Ignore)
impl.Name = @interface.Name + "." + impl.Name;
@class.Methods.Add(impl);
}
@interface.Properties.AddRange(@base.Properties.Where(p => !p.Ignore));
@class.Properties.AddRange(
from property in @interface.Properties
select new Property(property) { Namespace = @class });
@interface.Events.AddRange(@base.Events);
if (@base.Bases.All(b => b.Class != @interface))
@base.Bases.Add(new BaseClassSpecifier { Type = new TagType(@interface) });
interfaces.Add(@base, @interface);
return @interface;
}
}
}

8
tests/CSharpTemp/CSharpTemp.Tests.cs

@ -30,4 +30,12 @@ public class CSharpTempTests @@ -30,4 +30,12 @@ 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));
Assert.That(((IBar) baz).method(), Is.EqualTo(2));
}
}

10
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,6 +31,11 @@ const Foo& Bar::operator[](int i) const @@ -26,6 +31,11 @@ const Foo& Bar::operator[](int i) const
return m_foo;
}
int Bar::method()
{
return 2;
}
Foo& Bar::operator[](int i)
{
return m_foo;

7
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);
@ -20,9 +21,15 @@ protected: @@ -20,9 +21,15 @@ protected:
class DLL_API Bar
{
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
{
};

Loading…
Cancel
Save