From 6d2c0eaed857ce7e1de5b57e0f8d4220ebf70b1a Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Fri, 30 Aug 2013 23:31:14 +0300 Subject: [PATCH] Generated internal implementations of abstract classes in a new pass. Signed-off-by: Dimitar Dobrev --- src/Generator/Driver.cs | 1 + .../Generators/CSharp/CSharpMarshal.cs | 3 +- .../Generators/CSharp/CSharpTextTemplate.cs | 59 ++++++++-- .../Passes/AbstractImplementationsPass.cs | 105 ++++++++++++++++++ src/Generator/Passes/FindSymbolsPass.cs | 4 +- src/Generator/Utils/ParameterTypeComparer.cs | 18 +++ tests/Basic/Basic.h | 9 +- 7 files changed, 188 insertions(+), 11 deletions(-) create mode 100644 src/Generator/Passes/AbstractImplementationsPass.cs create mode 100644 src/Generator/Utils/ParameterTypeComparer.cs diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 5566a67a..19a1fef5 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -148,6 +148,7 @@ namespace CppSharp TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); TranslationUnitPasses.AddPass(new CheckFlagEnumsPass()); TranslationUnitPasses.AddPass(new CheckDuplicatedNamesPass()); + TranslationUnitPasses.AddPass(new AbstractImplementationsPass()); } public void ProcessCode() diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index fd976038..115feb18 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -252,7 +252,8 @@ namespace CppSharp.Generators.CSharp instance = instanceName; } - Context.Return.Write("new {0}({1})", QualifiedIdentifier(@class), + Context.Return.Write("new {0}({1})", + QualifiedIdentifier(@class) + (@class.IsAbstract ? "Internal" : ""), instance); return true; diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 82b8b709..7e8e3df1 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using CppSharp.AST; +using CppSharp.Utils; using Type = CppSharp.AST.Type; namespace CppSharp.Generators.CSharp @@ -402,9 +403,6 @@ namespace CppSharp.Generators.CSharp if (method.IsSynthetized) return; - if (method.IsPure) - return; - if (method.IsProxy) return; @@ -611,7 +609,22 @@ namespace CppSharp.Generators.CSharp if (@class.IsUnion) WriteLine("[StructLayout(LayoutKind.Explicit)]"); - Write("public unsafe "); + switch (@class.Access) + { + case AccessSpecifier.Private: + Write("internal "); + break; + case AccessSpecifier.Protected: + Write("protected "); + break; + case AccessSpecifier.Public: + Write("public "); + break; + } + Write("unsafe "); + + if (@class.IsAbstract) + Write("abstract "); if (Options.GeneratePartialClasses) Write("partial "); @@ -1459,9 +1472,9 @@ namespace CppSharp.Generators.CSharp PushBlock(CSharpBlockKind.Method); GenerateDeclarationCommon(method); - Write("public "); + Write(@class.IsAbstract && method.IsConstructor ? "protected " : "public "); - if (method.IsVirtual && !method.IsOverride) + if (method.IsVirtual && !method.IsOverride && !method.IsPure) Write("virtual "); var isBuiltinOperator = method.IsOperator && @@ -1473,6 +1486,9 @@ namespace CppSharp.Generators.CSharp if (method.IsOverride) Write("override "); + if (method.IsPure) + Write("abstract "); + var functionName = GetFunctionIdentifier(method); if (method.IsConstructor || method.IsDestructor) @@ -1482,7 +1498,15 @@ namespace CppSharp.Generators.CSharp GenerateMethodParameters(method); - WriteLine(")"); + Write(")"); + + if (method.IsPure) + { + Write(";"); + PopBlock(NewLineKind.BeforeNextBlock); + return; + } + NewLine(); if (method.Kind == CXXMethodKind.Constructor) GenerateClassConstructorBase(@class, method); @@ -1502,6 +1526,10 @@ namespace CppSharp.Generators.CSharp { GenerateOperator(method, @class); } + else if (method.IsOverride && method.IsSynthetized) + { + GenerateVirtualTableMethodCall(method, @class); + } else { GenerateInternalFunctionCall(method); @@ -1529,6 +1557,21 @@ namespace CppSharp.Generators.CSharp PopBlock(NewLineKind.BeforeNextBlock); } + private void GenerateVirtualTableMethodCall(ITypedDecl method, Class @class) + { + WriteLine("void* vtable = *((void**) __Instance.ToPointer());"); + int i; + switch (Driver.Options.Abi) + { + case CppAbi.Microsoft: + throw new NotImplementedException(); + default: + i = @class.Layout.Layout.Components.FindIndex(m => m.Method == method); + break; + } + WriteLine("void* slot = *((void**) vtable + {0} * sizeof(IntPtr));", i); + } + private void GenerateOperator(Method method, Class @class) { if (method.IsSynthetized) @@ -1974,7 +2017,7 @@ namespace CppSharp.Generators.CSharp public void GenerateInternalFunction(Function function) { - if (!function.IsProcessed || function.ExplicityIgnored) + if (!function.IsProcessed || function.ExplicityIgnored || function.IsPure) return; if (function.OriginalFunction != null) diff --git a/src/Generator/Passes/AbstractImplementationsPass.cs b/src/Generator/Passes/AbstractImplementationsPass.cs new file mode 100644 index 00000000..0e116364 --- /dev/null +++ b/src/Generator/Passes/AbstractImplementationsPass.cs @@ -0,0 +1,105 @@ +using System.Collections.Generic; +using System.Linq; +using CppSharp.AST; +using CppSharp.Utils; + +namespace CppSharp.Passes +{ + public class AbstractImplementationsPass : TranslationUnitPass + { + private readonly List classes = new List(); + + public override bool VisitTranslationUnit(TranslationUnit unit) + { + bool result = base.VisitTranslationUnit(unit); + unit.Classes.AddRange(classes); + classes.Clear(); + return result; + } + + public override bool VisitClassDecl(Class @class) + { + if (@class.CompleteDeclaration != null) + return VisitClassDecl(@class.CompleteDeclaration as Class); + + if (!VisitDeclaration(@class) || AlreadyVisited(@class)) + return false; + + if (@class.IsAbstract) + @classes.Add(AddInternalImplementation(@class)); + return base.VisitClassDecl(@class); + } + + private static Class AddInternalImplementation(Class @class) + { + var internalImplementation = new Class(); + internalImplementation.Name = @class.Name + "Internal"; + internalImplementation.Access = AccessSpecifier.Private; + internalImplementation.Namespace = @class.Namespace; + var @base = new BaseClassSpecifier { Type = new TagType(@class) }; + internalImplementation.Bases.Add(@base); + var abstractMethods = GetAbstractMethods(@class); + var overriddenMethods = GetOverriddenMethods(@class); + var parameterTypeComparer = new ParameterTypeComparer(); + for (int i = abstractMethods.Count - 1; i >= 0; i--) + { + Method @abstract = abstractMethods[i]; + if (overriddenMethods.Find(m => m.Name == @abstract.Name && + m.ReturnType.Type == @abstract.ReturnType.Type && + m.Parameters.Count == @abstract.Parameters.Count && + m.Parameters.SequenceEqual(@abstract.Parameters, parameterTypeComparer)) != null) + { + abstractMethods.RemoveAt(i); + } + } + internalImplementation.Methods.AddRange(from abstractMethod in abstractMethods + select new Method(abstractMethod)); + internalImplementation.Layout = new ClassLayout(@class.Layout); + var vTableComponents = GetVTableComponents(@class); + for (int i = 0; i < abstractMethods.Count; i++) + { + var vTableComponent = vTableComponents.Find(v => v.Method == abstractMethods[i]); + VTableComponent copy = new VTableComponent(); + copy.Kind = vTableComponent.Kind; + copy.Offset = vTableComponent.Offset; + copy.Declaration = internalImplementation.Methods[i]; + vTableComponents[vTableComponents.IndexOf(vTableComponent)] = copy; + } + internalImplementation.Layout.Layout.Components.Clear(); + internalImplementation.Layout.Layout.Components.AddRange(vTableComponents); + internalImplementation.Layout.VFTables.AddRange(@class.Layout.VFTables); + foreach (Method method in internalImplementation.Methods) + { + method.IsPure = false; + method.IsOverride = true; + method.IsSynthetized = true; + } + return internalImplementation; + } + + private static List GetAbstractMethods(Class @class) + { + var abstractMethods = @class.Methods.Where(m => m.IsPure).ToList(); + foreach (BaseClassSpecifier @base in @class.Bases) + abstractMethods.AddRange(GetAbstractMethods(@base.Class)); + return abstractMethods; + } + + private static List GetOverriddenMethods(Class @class) + { + var abstractMethods = @class.Methods.Where(m => m.IsOverride).ToList(); + foreach (BaseClassSpecifier @base in @class.Bases) + abstractMethods.AddRange(GetOverriddenMethods(@base.Class)); + return abstractMethods; + } + + private static List GetVTableComponents(Class @class) + { + List vTableComponents = new List( + @class.Layout.Layout.Components); + foreach (BaseClassSpecifier @base in @class.Bases) + vTableComponents.AddRange(GetVTableComponents(@base.Class)); + return vTableComponents; + } + } +} diff --git a/src/Generator/Passes/FindSymbolsPass.cs b/src/Generator/Passes/FindSymbolsPass.cs index 7d9ee99e..e7146d08 100644 --- a/src/Generator/Passes/FindSymbolsPass.cs +++ b/src/Generator/Passes/FindSymbolsPass.cs @@ -11,7 +11,9 @@ namespace CppSharp.Passes return false; var mangledDecl = decl as IMangledDecl; - if (mangledDecl != null && !VisitMangledDeclaration(mangledDecl)) + var method = decl as Method; + if (mangledDecl != null && !(method != null && method.IsPure) && + !VisitMangledDeclaration(mangledDecl)) { decl.ExplicityIgnored = true; return false; diff --git a/src/Generator/Utils/ParameterTypeComparer.cs b/src/Generator/Utils/ParameterTypeComparer.cs new file mode 100644 index 00000000..68f7e271 --- /dev/null +++ b/src/Generator/Utils/ParameterTypeComparer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using CppSharp.AST; + +namespace CppSharp.Utils +{ + public class ParameterTypeComparer : IEqualityComparer + { + public bool Equals(Parameter x, Parameter y) + { + return x.Type == y.Type; + } + + public int GetHashCode(Parameter obj) + { + return obj.Type.GetHashCode(); + } + } +} diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index d85e5a51..2a5f4d2c 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -80,6 +80,13 @@ public: Hello* RetNull(); }; +class DLL_API AbstractFoo +{ +public: + + virtual void pureFunction() = 0; +}; + DLL_API Bar operator-(const Bar &); DLL_API Bar operator+(const Bar &, const Bar &); @@ -112,4 +119,4 @@ struct DLL_API DefaultParameters void Bar() const; void Bar(); -}; \ No newline at end of file +};