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
// True if class provides pure virtual methods. // True if class provides pure virtual methods.
public bool IsAbstract; public bool IsAbstract;
public bool IsInterface { get; set; }
// True if the type is to be treated as a union. // True if the type is to be treated as a union.
public bool IsUnion; public bool IsUnion;

24
src/AST/Property.cs

@ -7,6 +7,30 @@ namespace CppSharp.AST
/// </summary> /// </summary>
public class Property : Declaration, ITypedDecl 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 public Type Type
{ {
get { return QualifiedType.Type; } get { return QualifiedType.Type; }

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

@ -30,8 +30,7 @@ namespace CppSharp.Generators.CSharp
public static string SafeIdentifier(string id) public static string SafeIdentifier(string id)
{ {
id = new string(((IEnumerable<char>)id) id = new string(id.Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
.Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
return Keywords.Contains(id) ? "@" + id : id; return Keywords.Contains(id) ? "@" + id : id;
} }
@ -220,7 +219,10 @@ namespace CppSharp.Generators.CSharp
if (@class.IsDependent) if (@class.IsDependent)
continue; continue;
GenerateClass(@class); if (@class.IsInterface)
GenerateInterface(@class);
else
GenerateClass(@class);
} }
if (context.HasFunctions) if (context.HasFunctions)
@ -356,6 +358,80 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock); 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) private void GenerateValueClassFields(Class @class)
{ {
GenerateClassFields(@class, field => GenerateClassFields(@class, field =>
@ -610,7 +686,7 @@ namespace CppSharp.Generators.CSharp
baseClass = @class.Bases[0].Class; baseClass = @class.Bases[0].Class;
var hasRefBase = baseClass != null && baseClass.IsRefType var hasRefBase = baseClass != null && baseClass.IsRefType
&& !baseClass.Ignore; && !baseClass.Ignore && !baseClass.IsInterface;
var hasIgnoredBase = baseClass != null && baseClass.Ignore; var hasIgnoredBase = baseClass != null && baseClass.Ignore;
@ -643,8 +719,9 @@ namespace CppSharp.Generators.CSharp
if (needsBase) if (needsBase)
{ {
var qualifiedBase = QualifiedIdentifier(@class.Bases[0].Class); Write("{0}", string.Join(", ",
Write("{0}", qualifiedBase); from @base in @class.Bases
select QualifiedIdentifier(@base.Class)));
if (@class.IsRefType) if (@class.IsRefType)
Write(", "); Write(", ");
@ -1360,7 +1437,8 @@ namespace CppSharp.Generators.CSharp
private void GenerateDisposeMethods(Class @class) 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. // Generate the IDispose Dispose() method.
if (!hasBaseClass) if (!hasBaseClass)
@ -1429,7 +1507,8 @@ namespace CppSharp.Generators.CSharp
WriteLine("internal {0}(global::System.IntPtr native){1}", safeIdentifier, WriteLine("internal {0}(global::System.IntPtr native){1}", safeIdentifier,
@class.IsValueType ? " : this()" : string.Empty); @class.IsValueType ? " : this()" : string.Empty);
var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType; var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType &&
!@class.BaseClass.IsInterface;
if (hasBaseClass) if (hasBaseClass)
WriteLineIndent(": base(native)"); WriteLineIndent(": base(native)");
@ -1523,14 +1602,18 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.Method); PushBlock(CSharpBlockKind.Method);
GenerateDeclarationCommon(method); GenerateDeclarationCommon(method);
switch (GetValidMethodAccess(method, @class)) // check if this is an explicit interface implementation
if (!method.Name.Contains('.'))
{ {
case AccessSpecifier.Public: switch (GetValidMethodAccess(method, @class))
Write("public "); {
break; case AccessSpecifier.Public:
case AccessSpecifier.Protected: Write("public ");
Write("protected "); break;
break; case AccessSpecifier.Protected:
Write("protected ");
break;
}
} }
if (method.IsVirtual && !method.IsOverride && if (method.IsVirtual && !method.IsOverride &&
@ -1549,7 +1632,8 @@ namespace CppSharp.Generators.CSharp
if (Driver.Options.GenerateAbstractImpls && method.IsPure) if (Driver.Options.GenerateAbstractImpls && method.IsPure)
Write("abstract "); Write("abstract ");
var functionName = GetFunctionIdentifier(method); var functionName = method.IsOperator ?
Operators.GetOperatorIdentifier(method.OperatorKind) : method.Name;
if (method.IsConstructor || method.IsDestructor) if (method.IsConstructor || method.IsDestructor)
Write("{0}(", functionName); Write("{0}(", functionName);

53
src/Generator/Passes/MultipleInheritancePass.cs

@ -25,18 +25,53 @@ namespace CppSharp.Passes
for (int i = 1; i < @class.Bases.Count; i++) for (int i = 1; i < @class.Bases.Count; i++)
{ {
var @base = @class.Bases[i].Class; var @base = @class.Bases[i].Class;
if (@base.IsInterface) continue;
if (@base.CompleteDeclaration != null)
@base = (Class) @base.CompleteDeclaration;
var name = "I" + @base.Name; var name = "I" + @base.Name;
if (!interfaces.ContainsKey(@base) && @base.Namespace.Classes.All(c => c.Name != name)) var @interface = (interfaces.ContainsKey(@base)
{ ? interfaces[@base]
Class @interface = new Class { Name = name, Namespace = @class.Namespace }; : @base.Namespace.Classes.FirstOrDefault(c => c.Name == name)) ??
@interface.IsAbstract = true; GetNewInterface(@class, name, @base);
@interface.Methods.AddRange(@class.Methods); @class.Bases[i] = new BaseClassSpecifier { Type = new TagType(@interface) };
@interface.Properties.AddRange(@class.Properties);
@interface.Events.AddRange(@class.Events);
@interfaces.Add(@class, @interface);
}
} }
return base.VisitClassDecl(@class); 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
Assert.That(typeof(Foo).GetProperty("P", Assert.That(typeof(Foo).GetProperty("P",
BindingFlags.Instance | BindingFlags.NonPublic), Is.Not.Null); 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()
P = 50; P = 50;
} }
int Foo::method()
{
return 1;
}
int Foo::operator[](int i) const int Foo::operator[](int i) const
{ {
return 5; return 5;
@ -26,6 +31,11 @@ const Foo& Bar::operator[](int i) const
return m_foo; return m_foo;
} }
int Bar::method()
{
return 2;
}
Foo& Bar::operator[](int i) Foo& Bar::operator[](int i)
{ {
return m_foo; return m_foo;

7
tests/CSharpTemp/CSharpTemp.h

@ -8,6 +8,7 @@ class DLL_API Foo
{ {
public: public:
Foo(); Foo();
int method();
int operator[](int i) const; int operator[](int i) const;
int operator[](unsigned int i); int operator[](unsigned int i);
int& operator[](int i); int& operator[](int i);
@ -20,9 +21,15 @@ protected:
class DLL_API Bar class DLL_API Bar
{ {
public: public:
int method();
const Foo& operator[](int i) const; const Foo& operator[](int i) const;
Foo& operator[](int i); Foo& operator[](int i);
private: private:
Foo m_foo; Foo m_foo;
}; };
class DLL_API Baz : public Foo, public Bar
{
};

Loading…
Cancel
Save