From c9e5c0d505d710267e83b4afd6324ff4af10d706 Mon Sep 17 00:00:00 2001
From: Dimitar Dobrev <dpldobrev@yahoo.com>
Date: Thu, 19 Sep 2013 15:59:24 +0300
Subject: [PATCH] Completed the parallel hierarchy of interfaces so that a
 derived class can access the members of all of its bases.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>
---
 src/AST/Class.cs                              | 10 +--
 .../Generators/CSharp/CSharpTextTemplate.cs   | 21 ++----
 .../Passes/MultipleInheritancePass.cs         | 64 +++++++++++++------
 tests/CSharpTemp/CSharpTemp.cpp               |  5 ++
 tests/CSharpTemp/CSharpTemp.h                 |  8 ++-
 5 files changed, 68 insertions(+), 40 deletions(-)

diff --git a/src/AST/Class.cs b/src/AST/Class.cs
index 4b040991..42a1aafa 100644
--- a/src/AST/Class.cs
+++ b/src/AST/Class.cs
@@ -203,9 +203,10 @@ namespace CppSharp.AST
             }
         }
 
-        public Method GetRootBaseMethod(Method @override)
+        public Method GetRootBaseMethod(Method @override, bool onlyFirstBase = false)
         {
             return (from @base in Bases
+                    where !@base.Class.IsInterface
                     let baseMethod = (
                         from method in @base.Class.Methods
                         where
@@ -216,13 +217,14 @@ namespace CppSharp.AST
                                                             new ParameterTypeComparer())
                         select method).FirstOrDefault()
                     let rootBaseMethod = @base.Class.GetRootBaseMethod(@override) ?? baseMethod
-                    where rootBaseMethod != null
+                    where rootBaseMethod != null || onlyFirstBase
                     select rootBaseMethod).FirstOrDefault();
         }
 
-        public Property GetRootBaseProperty(Property @override)
+        public Property GetRootBaseProperty(Property @override, bool onlyFirstBase = false)
         {
             return (from @base in Bases
+                    where !@base.Class.IsInterface
                     let baseProperty = (
                         from property in @base.Class.Properties
                         where
@@ -232,7 +234,7 @@ namespace CppSharp.AST
                                                             new ParameterTypeComparer())
                         select property).FirstOrDefault()
                     let rootBaseProperty = @base.Class.GetRootBaseProperty(@override) ?? baseProperty
-                    where rootBaseProperty != null
+                    where rootBaseProperty != null || onlyFirstBase
                     select rootBaseProperty).FirstOrDefault();
         }
 
diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs
index a7588177..3a9c234e 100644
--- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs
+++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs
@@ -375,21 +375,12 @@ namespace CppSharp.Generators.CSharp
             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(", ");
-            //}
+            if (@class.HasBase)
+            {
+                Write(" : {0}", string.Join(", ",
+                    from @base in @class.Bases
+                    select QualifiedIdentifier(@base.Class)));   
+            }
 
             NewLine();
             WriteStartBraceIndent();
diff --git a/src/Generator/Passes/MultipleInheritancePass.cs b/src/Generator/Passes/MultipleInheritancePass.cs
index d6ca1166..0ffe9570 100644
--- a/src/Generator/Passes/MultipleInheritancePass.cs
+++ b/src/Generator/Passes/MultipleInheritancePass.cs
@@ -27,19 +27,25 @@ namespace CppSharp.Passes
                 var @base = @class.Bases[i].Class;
                 if (@base.IsInterface) continue;
 
-                if (@base.CompleteDeclaration != null)
-                    @base = (Class) @base.CompleteDeclaration;
-                var name = "I" + @base.Name;
-                var @interface = (interfaces.ContainsKey(@base)
-                    ? interfaces[@base]
-                    : @base.Namespace.Classes.FirstOrDefault(c => c.Name == name)) ??
-                                 GetNewInterface(@class, name, @base);
+                var @interface = GetInterface(@class, @base, true);
                 @class.Bases[i] = new BaseClassSpecifier { Type = new TagType(@interface) };
             }
             return base.VisitClassDecl(@class);
         }
 
-        private Class GetNewInterface(Class @class, string name, Class @base)
+        private Class GetInterface(Class @class, Class @base, bool addMembers = false)
+        {
+            if (@base.CompleteDeclaration != null)
+                @base = (Class) @base.CompleteDeclaration;
+            var name = "I" + @base.Name;
+            var @interface = (this.interfaces.ContainsKey(@base)
+                ? this.interfaces[@base]
+                : @base.Namespace.Classes.FirstOrDefault(c => c.Name == name)) ??
+                             GetNewInterface(@class, name, @base, addMembers);
+            return @interface;
+        }
+
+        private Class GetNewInterface(Class @class, string name, Class @base, bool addMembers = false)
         {
             var @interface = new Class
                 {
@@ -48,8 +54,27 @@ namespace CppSharp.Passes
                     Access = @base.Access,
                     IsInterface = true
                 };
+            @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));
+            @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)
@@ -58,28 +83,27 @@ namespace CppSharp.Passes
                         IsVirtual = false,
                         IsOverride = false
                     };
-                var rootBaseMethod = @class.GetRootBaseMethod(method);
+                var rootBaseMethod = @class.GetRootBaseMethod(method, true);
                 if (rootBaseMethod != null && !rootBaseMethod.Ignore)
                     impl.Name = @interface.Name + "." + impl.Name;
                 @class.Methods.Add(impl);
             }
-            @interface.Properties.AddRange(@base.Properties.Where(p => !p.Ignore));
+            foreach (var @base in @interface.Bases)
+                ImplementInterfaceMethods(@class, @base.Class);
+        }
+
+        private static void ImplementInterfaceProperties(Class @class, Class @interface)
+        {
             foreach (var property in @interface.Properties)
             {
-                var impl = new Property(property)
-                    {
-                        Namespace = @class
-                    };
-                var rootBaseProperty = @class.GetRootBaseProperty(property);
+                var impl = new Property(property) { Namespace = @class };
+                var rootBaseProperty = @class.GetRootBaseProperty(property, true);
                 if (rootBaseProperty != null && !rootBaseProperty.Ignore)
                     impl.Name = @interface.Name + "." + impl.Name;
                 @class.Properties.Add(impl);
             }
-            @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;
+            foreach (var @base in @interface.Bases)
+                ImplementInterfaceProperties(@class, @base.Class);
         }
     }
 }
diff --git a/tests/CSharpTemp/CSharpTemp.cpp b/tests/CSharpTemp/CSharpTemp.cpp
index b0882e34..250ba462 100644
--- a/tests/CSharpTemp/CSharpTemp.cpp
+++ b/tests/CSharpTemp/CSharpTemp.cpp
@@ -31,6 +31,11 @@ const Foo& Bar::operator[](int i) const
     return m_foo;
 }
 
+int Qux::farAwayFunc()
+{
+    return 20;
+}
+
 int Bar::method()
 {
     return 2;
diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h
index 001c658c..f23fd473 100644
--- a/tests/CSharpTemp/CSharpTemp.h
+++ b/tests/CSharpTemp/CSharpTemp.h
@@ -18,7 +18,13 @@ protected:
     int P;
 };
 
-class DLL_API Bar
+class DLL_API Qux
+{
+public:
+    int farAwayFunc();
+};
+
+class DLL_API Bar : public Qux
 {
 public:
     int method();