diff --git a/src/AST/Function.cs b/src/AST/Function.cs index 8dcaebcc..ff15e5c4 100644 --- a/src/AST/Function.cs +++ b/src/AST/Function.cs @@ -94,7 +94,8 @@ namespace CppSharp.AST ComplementOperator, AbstractImplCall, DefaultValueOverload, - InterfaceInstance + InterfaceInstance, + AdjustedMethod } public class Function : Declaration, ITypedDecl, IMangledDecl diff --git a/src/AST/Method.cs b/src/AST/Method.cs index c2216eba..5ba6361a 100644 --- a/src/AST/Method.cs +++ b/src/AST/Method.cs @@ -95,6 +95,7 @@ namespace CppSharp.AST IsMoveConstructor = method.IsMoveConstructor; Conversion = method.Conversion; SynthKind = method.SynthKind; + AdjustedOffset = method.AdjustedOffset; } public Method(Function function) @@ -148,6 +149,8 @@ namespace CppSharp.AST public Class ExplicitInterfaceImpl { get; set; } + public int AdjustedOffset { get; set; } + public override T Visit(IDeclVisitor visitor) { return visitor.VisitMethodDecl(this); diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index fafa82f9..b8a52db0 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -496,7 +496,8 @@ namespace CppSharp.Generators.CSharp Action tryAddOverload = method => { - if (method.IsSynthetized) + if (method.IsSynthetized && + method.SynthKind != FunctionSynthKind.AdjustedMethod) return; if (method.IsProxy) @@ -2298,6 +2299,8 @@ namespace CppSharp.Generators.CSharp else { names.Insert(instanceIndex, Helpers.InstanceIdentifier); + if (method.SynthKind == FunctionSynthKind.AdjustedMethod) + names[instanceIndex] += " + " + method.AdjustedOffset.ToString(); } } } diff --git a/src/Generator/Passes/MultipleInheritancePass.cs b/src/Generator/Passes/MultipleInheritancePass.cs index 23bd1ee7..57b3c314 100644 --- a/src/Generator/Passes/MultipleInheritancePass.cs +++ b/src/Generator/Passes/MultipleInheritancePass.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using CppSharp.AST; using CppSharp.Generators.CSharp; @@ -24,10 +25,79 @@ namespace CppSharp.Passes return result; } + public static bool ComputeClassPath(Class current, Class target, + List 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 ComputeClassPath(Class from, Class to) + { + var path = new List(); + + 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 (AlreadyVisited(@class)) + return false; + + CheckNonVirtualInheritedFunctions(@class); + // skip the first base because we can inherit from one class - for (int i = 1; i < @class.Bases.Count; i++) + for (var i = 1; i < @class.Bases.Count; i++) { var @base = @class.Bases[i].Class; if (@base.IsInterface) continue; diff --git a/src/Generator/Passes/RenamePass.cs b/src/Generator/Passes/RenamePass.cs index 059ace93..c500e397 100644 --- a/src/Generator/Passes/RenamePass.cs +++ b/src/Generator/Passes/RenamePass.cs @@ -105,7 +105,7 @@ namespace CppSharp.Passes declarations.AddRange(decl.Namespace.Enums); declarations.AddRange(decl.Namespace.Events); var function = decl as Function; - if (function != null) + if (function != null && function.SynthKind != FunctionSynthKind.AdjustedMethod) { // account for overloads declarations.AddRange(GetFunctionsWithTheSameParams(function)); diff --git a/tests/CSharpTemp/CSharpTemp.Tests.cs b/tests/CSharpTemp/CSharpTemp.Tests.cs index a591064d..ca80d376 100644 --- a/tests/CSharpTemp/CSharpTemp.Tests.cs +++ b/tests/CSharpTemp/CSharpTemp.Tests.cs @@ -188,4 +188,16 @@ public class CSharpTempTests : GeneratorTestFixture { Assert.AreEqual(5, Foo.Rename); } + + [Test, Ignore] + public void TestPrimarySecondaryBase() + { + var a = new MI_A0(); + var resa = a.Get(); + Assert.That(resa, Is.EqualTo(50)); + + var c = new MI_C(); + var res = c.Get(); + Assert.That(res, Is.EqualTo(50)); + } } \ No newline at end of file diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index 2a4812d8..881026da 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -312,6 +312,41 @@ private: IgnoredType _ignoredType; }; +// --- Multiple inheritance + +struct DLL_API MI_A0 +{ + MI_A0(); + int get(); + int F; +}; + +MI_A0::MI_A0() : F(50) {} +int MI_A0::get() { return F; }; + +struct DLL_API MI_A +{ + MI_A(); + virtual void v(int i = 5); +}; + +MI_A::MI_A() {} +void MI_A::v(int i) {} + +struct DLL_API MI_B : public MI_A +{ + MI_B(); +}; + +MI_B::MI_B() {} + +struct DLL_API MI_C : public MI_A0, public MI_B +{ + MI_C(); +}; + +MI_C::MI_C() {} + class DLL_API StructWithPrivateFields { public: