diff --git a/src/AST/Function.cs b/src/AST/Function.cs index a9043167..04a20a0a 100644 --- a/src/AST/Function.cs +++ b/src/AST/Function.cs @@ -165,27 +165,30 @@ namespace CppSharp.AST public virtual QualifiedType GetFunctionType() { - var functionType = new FunctionType(); - functionType.CallingConvention = CallingConvention; - functionType.ReturnType = ReturnType; + var functionType = new FunctionType + { + CallingConvention = this.CallingConvention, + ReturnType = this.ReturnType + }; functionType.Parameters.AddRange(Parameters); + ReplaceIndirectReturnParamWithRegular(functionType); + var pointerType = new PointerType { QualifiedPointee = new QualifiedType(functionType) }; + return new QualifiedType(pointerType); + } + + private static void ReplaceIndirectReturnParamWithRegular(FunctionType functionType) + { for (int i = functionType.Parameters.Count - 1; i >= 0; i--) { var parameter = functionType.Parameters[i]; if (parameter.Kind == ParameterKind.IndirectReturnType) { - var retParam = new Parameter(); - retParam.Name = parameter.Name; - var ptrType = new PointerType(); - ptrType.QualifiedPointee = new QualifiedType(parameter.Type); - retParam.QualifiedType = new QualifiedType(ptrType); + var ptrType = new PointerType { QualifiedPointee = new QualifiedType(parameter.Type) }; + var retParam = new Parameter { Name = parameter.Name, QualifiedType = new QualifiedType(ptrType) }; functionType.Parameters.RemoveAt(i); functionType.Parameters.Insert(i, retParam); } } - var pointerType = new PointerType(); - pointerType.QualifiedPointee = new QualifiedType(functionType); - return new QualifiedType(pointerType); } } } \ No newline at end of file diff --git a/src/AST/Method.cs b/src/AST/Method.cs index 9a21f371..74285471 100644 --- a/src/AST/Method.cs +++ b/src/AST/Method.cs @@ -127,10 +127,11 @@ namespace CppSharp.AST { FunctionType functionType; qualifiedType.Type.IsPointerTo(out functionType); - var instance = new Parameter(); - instance.Name = "instance"; - instance.QualifiedType = new QualifiedType( - new BuiltinType(PrimitiveType.IntPtr)); + var instance = new Parameter + { + Name = "instance", + QualifiedType = new QualifiedType(new BuiltinType(PrimitiveType.IntPtr)) + }; functionType.Parameters.Insert(0, instance); } return qualifiedType; diff --git a/src/Generator/AST/VTables.cs b/src/Generator/AST/VTables.cs index d3894996..edd24d44 100644 --- a/src/Generator/AST/VTables.cs +++ b/src/Generator/AST/VTables.cs @@ -83,41 +83,18 @@ namespace CppSharp.AST throw new NotSupportedException(); } - public static string GetVirtualCallDelegate(INamedDecl method, Class @class, - bool is32Bit, out string delegateId) + public static int GetVTableIndex(INamedDecl method, Class @class) { - var virtualCallBuilder = new StringBuilder(); - virtualCallBuilder.AppendFormat( - "void* vtable = *((void**) {0}.ToPointer());", - Helpers.InstanceIdentifier); - virtualCallBuilder.AppendLine(); - - int i; switch (@class.Layout.ABI) { case CppAbi.Microsoft: - i = (from table in @class.Layout.VFTables - let j = table.Layout.Components.FindIndex(m => m.Method == method) - where j >= 0 - select j).First(); - break; + return (from table in @class.Layout.VFTables + let j = table.Layout.Components.FindIndex(m => m.Method == method) + where j >= 0 + select j).First(); default: - i = @class.Layout.Layout.Components.FindIndex(m => m.Method == method); - break; + return @class.Layout.Layout.Components.FindIndex(m => m.Method == method); } - - virtualCallBuilder.AppendFormat( - "void* slot = *((void**) vtable + {0} * {1});", i, is32Bit ? 4 : 8); - virtualCallBuilder.AppendLine(); - - string @delegate = method.Name + "Delegate"; - delegateId = Generator.GeneratedIdentifier(@delegate); - - virtualCallBuilder.AppendFormat( - "var {1} = ({0}) Marshal.GetDelegateForFunctionPointer(new IntPtr(slot), typeof({0}));", - @delegate, delegateId); - virtualCallBuilder.AppendLine(); - return virtualCallBuilder.ToString(); } } } diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index cfa1821f..83c11c47 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -626,8 +626,7 @@ namespace CppSharp.Generators.CSharp Write(Helpers.GetAccess(@class)); Write("unsafe "); - if (Driver.Options.GenerateAbstractImpls && - @class.IsAbstract) + if (Driver.Options.GenerateAbstractImpls && @class.IsAbstract) Write("abstract "); if (Options.GeneratePartialClasses) @@ -1365,8 +1364,7 @@ namespace CppSharp.Generators.CSharp PushBlock(CSharpBlockKind.Method); string className = @class.Name; string safeIdentifier = SafeIdentifier(className); - if (@class.Access == AccessSpecifier.Private && - className.EndsWith("Internal")) + if (@class.Access == AccessSpecifier.Private && className.EndsWith("Internal")) { className = className.Substring(0, safeIdentifier.LastIndexOf("Internal", StringComparison.Ordinal)); @@ -1379,8 +1377,7 @@ namespace CppSharp.Generators.CSharp PopBlock(NewLineKind.BeforeNextBlock); PushBlock(CSharpBlockKind.Method); - WriteLine("internal {0}({1}.Internal native)", safeIdentifier, - className); + WriteLine("internal {0}({1}.Internal native)", safeIdentifier, className); WriteLineIndent(": this(&native)"); WriteStartBraceIndent(); WriteCloseBraceIndent(); @@ -1574,10 +1571,34 @@ namespace CppSharp.Generators.CSharp private void GenerateVirtualTableFunctionCall(Function method, Class @class) { string delegateId; - Write(VTables.GetVirtualCallDelegate(method, @class, Driver.Options.Is32Bit, out delegateId)); + Write(GetVirtualCallDelegate(method, @class, Driver.Options.Is32Bit, out delegateId)); GenerateFunctionCall(delegateId, method.Parameters, method); } + public static string GetVirtualCallDelegate(INamedDecl method, Class @class, + bool is32Bit, out string delegateId) + { + var virtualCallBuilder = new StringBuilder(); + virtualCallBuilder.AppendFormat("void* vtable = *((void**) {0}.ToPointer());", + Helpers.InstanceIdentifier); + virtualCallBuilder.AppendLine(); + + var i = VTables.GetVTableIndex(method, @class); + + virtualCallBuilder.AppendFormat( + "void* slot = *((void**) vtable + {0} * {1});", i, is32Bit ? 4 : 8); + virtualCallBuilder.AppendLine(); + + string @delegate = method.Name + "Delegate"; + delegateId = Generator.GeneratedIdentifier(@delegate); + + virtualCallBuilder.AppendFormat( + "var {1} = ({0}) Marshal.GetDelegateForFunctionPointer(new IntPtr(slot), typeof({0}));", + @delegate, delegateId); + virtualCallBuilder.AppendLine(); + return virtualCallBuilder.ToString(); + } + private void GenerateOperator(Method method, Class @class) { if (method.IsSynthetized) diff --git a/src/Generator/Passes/GenerateAbstractImplementationsPass.cs b/src/Generator/Passes/GenerateAbstractImplementationsPass.cs index ee8c1e1f..951650c1 100644 --- a/src/Generator/Passes/GenerateAbstractImplementationsPass.cs +++ b/src/Generator/Passes/GenerateAbstractImplementationsPass.cs @@ -5,6 +5,11 @@ using CppSharp.Utils; namespace CppSharp.Passes { + /// + /// This pass generates internal classes that implement abstract classes. + /// When the return type of a function is abstract, these internal classes provide - + /// since the real type cannot be resolved while binding - an allocatable class that supports proper polymorphism. + /// public class GenerateAbstractImplementationsPass : TranslationUnitPass { private readonly List classes = new List(); @@ -39,9 +44,12 @@ namespace CppSharp.Passes foreach (var abstractMethod in abstractMethods) { internalImpl.Methods.Add(new Method(abstractMethod)); - var @delegate = new TypedefDecl { Name = abstractMethod.Name + "Delegate" }; - @delegate.QualifiedType = abstractMethod.GetFunctionType(); - @delegate.IgnoreFlags = abstractMethod.IgnoreFlags; + var @delegate = new TypedefDecl + { + Name = abstractMethod.Name + "Delegate", + QualifiedType = abstractMethod.GetFunctionType(), + IgnoreFlags = abstractMethod.IgnoreFlags + }; internalImpl.Typedefs.Add(@delegate); } @@ -59,10 +67,12 @@ namespace CppSharp.Passes private static Class GetInternalImpl(Declaration @class) { - var internalImpl = new Class(); - internalImpl.Name = @class.Name + "Internal"; - internalImpl.Access = AccessSpecifier.Private; - internalImpl.Namespace = @class.Namespace; + var internalImpl = new Class + { + Name = @class.Name + "Internal", + Access = AccessSpecifier.Private, + Namespace = @class.Namespace + }; var @base = new BaseClassSpecifier { Type = new TagType(@class) }; internalImpl.Bases.Add(@base); return internalImpl;