diff --git a/src/AST/TypeExtensions.cs b/src/AST/TypeExtensions.cs index 9165713f..ebbfe5de 100644 --- a/src/AST/TypeExtensions.cs +++ b/src/AST/TypeExtensions.cs @@ -90,26 +90,19 @@ if (ptr == null) return false; return ptr.Pointee.IsPrimitiveType(primitive); - } - - public static bool IsPointerTo(this Type t, out T type) where T : Type - { - var ptr = t as PointerType; - - if (ptr == null) - { - var functionPointer = t as MemberPointerType; - if (functionPointer != null) - { - type = functionPointer.Pointee as T; - return type != null; - } - type = null; - return false; - } - - type = ptr.Pointee as T; - return type != null; + } + + public static bool IsPointerTo(this Type t, out T type) where T : Type + { + var pointee = t.GetPointee(); + type = pointee as T; + if (type == null) + { + var attributedType = pointee as AttributedType; + if (attributedType != null) + type = attributedType.Modified.Type as T; + } + return type != null; } public static bool IsTagDecl(this Type t, out T decl) where T : Declaration @@ -154,6 +147,39 @@ } return t; + } + + /// + /// If t is a pointer type the type pointed to by t will be returned. + /// Otherwise null. + /// + public static Type GetPointee(this Type t) + { + var ptr = t as PointerType; + if (ptr != null) + return ptr.Pointee; + var memberPtr = t as MemberPointerType; + if (memberPtr != null) + return memberPtr.Pointee; + return null; + } + + /// + /// If t is a pointer type the type pointed to by t will be returned + /// after fully dereferencing it. Otherwise null. + /// For example int** -> int. + /// + public static Type GetFinalPointee(this Type t) + { + var finalPointee = t.GetPointee(); + var pointee = finalPointee; + while (pointee != null) + { + pointee = pointee.GetPointee(); + if (pointee != null) + finalPointee = pointee; + } + return finalPointee; } } } \ No newline at end of file diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 4654ab81..4b49a012 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -615,16 +615,19 @@ namespace CppSharp.Generators.CLI public void GenerateIndexer(Property property) { - var type = property.QualifiedType.Visit(TypePrinter); + var type = property.QualifiedType.Visit(TypePrinter); + var getter = property.GetMethod; + var indexParameter = getter.Parameters[0]; + var indexParameterType = indexParameter.QualifiedType.Visit(TypePrinter); - WriteLine("property {0} default[int]", type); + WriteLine("property {0} default[{1}]", type, indexParameterType); WriteStartBraceIndent(); - if (property.HasGetter) - WriteLine("{0} get(int index);", type); + if (property.HasGetter) + WriteLine("{0} get({1} {2});", type, indexParameterType, indexParameter.Name); - if (property.HasSetter) - WriteLine("void set(int index, {0});", type); + if (property.HasSetter) + WriteLine("void set({1} {2}, {0} value);", type, indexParameterType, indexParameter.Name); WriteCloseBraceIndent(); } @@ -635,7 +638,10 @@ namespace CppSharp.Generators.CLI return; PushBlock(CLIBlockKind.Property, property); - var type = property.QualifiedType.Visit(TypePrinter); + var type = property.QualifiedType.Visit(TypePrinter); + + if (property.IsStatic) + Write("static "); if (property.IsIndexer) { diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index 5d32143b..4f840c2d 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -90,12 +90,16 @@ namespace CppSharp.Generators.CLI } if (pointee.IsPrimitiveType(out primitive)) - { + { + var returnVarName = Context.ReturnVarName; + if (quals.IsConst != Context.ReturnType.Qualifiers.IsConst) + returnVarName = string.Format("const_cast<{0}>({1})", + Context.ReturnType, Context.ReturnVarName); if (pointer.Pointee is TypedefType) - Context.Return.Write("reinterpret_cast<{0}>({1})", pointer, - Context.ReturnVarName); - else - Context.Return.Write(Context.ReturnVarName); + Context.Return.Write("reinterpret_cast<{0}>({1})", pointer, + returnVarName); + else + Context.Return.Write(returnVarName); return true; } @@ -436,10 +440,10 @@ namespace CppSharp.Generators.CLI if (Context.Function == null) Context.Return.Write("&"); return pointee.Visit(this, quals); - } - - PrimitiveType primitive; - if (pointee.IsPrimitiveType(out primitive)) + } + + var finalPointee = pointer.GetFinalPointee(); + if (finalPointee.IsPrimitiveType()) { var cppTypePrinter = new CppTypePrinter(Context.Driver.TypeDatabase); var cppTypeName = pointer.Visit(cppTypePrinter, quals); @@ -506,7 +510,7 @@ namespace CppSharp.Generators.CLI } PrimitiveType primitive; - if (decl.Type.Desugar().IsPrimitiveType(out primitive)) + if (decl.Type.IsPrimitiveType(out primitive)) { Context.Return.Write("(::{0})", typedef.Declaration.QualifiedOriginalName); } diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index 1102ff97..6182d191 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -329,36 +329,37 @@ namespace CppSharp.Generators.CLI GeneratePropertyGetter(property.GetMethod, realOwner, property.Name, property.Type); - if (property.HasSetter) - GeneratePropertySetter(property.SetMethod, realOwner, property.Name, - property.Type); + if (property.HasSetter) + if (property.IsIndexer) + GeneratePropertySetter(property.SetMethod, realOwner, property.Name, + property.Type, property.GetMethod.Parameters[0]); + else + GeneratePropertySetter(property.SetMethod, realOwner, property.Name, + property.Type); } PopBlock(); - } - - private void GeneratePropertySetter(T decl, Class @class, string name, Type type) + } + + private void GeneratePropertySetter(T decl, Class @class, string name, Type type, Parameter indexParameter = null) where T : Declaration, ITypedDecl { if (decl == null) - return; + return; - var method = decl as Method; - var isIndexer = method != null && - method.OperatorKind == CXXOperatorKind.Subscript; - - var args = new List(); - if (isIndexer) - args.Add("int index"); + var args = new List(); + var isIndexer = indexParameter != null; + if (isIndexer) + args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name)); var function = decl as Function; - var argName = function != null ? function.Parameters[0].Name : "value"; + var argName = function != null && !isIndexer ? function.Parameters[0].Name : "value"; args.Add(string.Format("{0} {1}", type, argName)); WriteLine("void {0}::{1}::set({2})", QualifiedIdentifier(@class), name, string.Join(", ", args)); - WriteStartBraceIndent(); - + WriteStartBraceIndent(); + if (decl is Function && !isIndexer) { var func = decl as Function; @@ -397,7 +398,7 @@ namespace CppSharp.Generators.CLI @class.QualifiedOriginalName, decl.OriginalName); if (isIndexer) - variable += "(index)"; + variable += string.Format("({0})", indexParameter.Name); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); @@ -419,9 +420,12 @@ namespace CppSharp.Generators.CLI var isIndexer = method != null && method.OperatorKind == CXXOperatorKind.Subscript; - var args = new List(); - if (isIndexer) - args.Add("int index"); + var args = new List(); + if (isIndexer) + { + var indexParameter = method.Parameters[0]; + args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name)); + } WriteLine("{0} {1}::{2}::get({3})", type, QualifiedIdentifier(@class), name, string.Join(", ", args)); @@ -966,7 +970,7 @@ namespace CppSharp.Generators.CLI if (Driver.Options.MarshalCharAsManagedChar) { foreach (var param in method.Parameters.Where( - p => p.Type.Desugar().IsPrimitiveType(PrimitiveType.Int8))) + p => p.Type.IsPrimitiveType(PrimitiveType.Int8))) { WriteLine("if ({0} < System::Char::MinValue || {0} > System::SByte::MaxValue)", param.Name); WriteLineIndent( diff --git a/src/Generator/Generators/CLI/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index 84c9914b..2ab36616 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -1,386 +1,394 @@ -using System; -using System.Collections.Generic; -using CppSharp.AST; -using CppSharp.AST.Extensions; -using CppSharp.Types; -using Type = CppSharp.AST.Type; - -namespace CppSharp.Generators.CLI -{ - public class CLITypePrinterContext : TypePrinterContext - { - public CLITypePrinterContext() - { - - } - - public CLITypePrinterContext(TypePrinterContextKind kind) - : base(kind) - { - } - } - - public class CLITypePrinter : ITypePrinter, IDeclVisitor - { - public Driver Driver { get; set; } - public CLITypePrinterContext Context { get; set; } - - readonly ITypeMapDatabase TypeMapDatabase; - readonly DriverOptions Options; - - public CLITypePrinter(Driver driver) - { - Driver = driver; - TypeMapDatabase = driver.TypeDatabase; - Options = driver.Options; - Context = new CLITypePrinterContext(); - } - - public CLITypePrinter(Driver driver, CLITypePrinterContext context) - : this(driver) - { - Context = context; - } - - public string VisitTagType(TagType tag, TypeQualifiers quals) - { - TypeMap typeMap = null; - if (TypeMapDatabase.FindTypeMap(tag, out typeMap)) - { - typeMap.Type = tag; - Context.Type = tag; - return typeMap.CLISignature(Context); - } - - Declaration decl = tag.Declaration; - - if (decl == null) - return string.Empty; - - return VisitDeclaration(decl, quals); - } - - public string VisitArrayType(ArrayType array, TypeQualifiers quals) - { - return string.Format("cli::array<{0}>^", array.Type.Visit(this)); - } - - public string VisitFunctionType(FunctionType function, TypeQualifiers quals) - { - var arguments = function.Parameters; - var returnType = function.ReturnType; - var args = string.Empty; - - if (arguments.Count > 0) - args = VisitParameters(function.Parameters, hasNames: false); - - if (returnType.Type.IsPrimitiveType(PrimitiveType.Void)) - { - if (!string.IsNullOrEmpty(args)) - args = string.Format("<{0}>", args); - return string.Format("System::Action{0}", args); - } - - if (!string.IsNullOrEmpty(args)) - args = string.Format(", {0}", args); - - return string.Format("System::Func<{0}{1}>", returnType.Visit(this), args); - } - - public string VisitParameters(IEnumerable @params, - bool hasNames) - { - var args = new List(); - - foreach (var param in @params) - args.Add(VisitParameter(param, hasNames)); - - return string.Join(", ", args); - } - - public string VisitParameter(Parameter param, bool hasName = true) - { - Context.Parameter = param; - var type = param.Type.Visit(this, param.QualifiedType.Qualifiers); - Context.Parameter = null; - - var str = string.Empty; - if(param.Usage == ParameterUsage.Out) - str += "[System::Runtime::InteropServices::Out] "; - - str += type; - - if(param.Usage == ParameterUsage.Out || - param.Usage == ParameterUsage.InOut) - str += "%"; - - if (hasName && !string.IsNullOrEmpty(param.Name)) - str += " " + param.Name; - - return str; - } - - public string VisitDelegate(FunctionType function) - { - return string.Format("delegate {0} {{0}}({1})", - function.ReturnType.Visit(this), - VisitParameters(function.Parameters, hasNames: true)); - } - - public string VisitPointerType(PointerType pointer, TypeQualifiers quals) - { - var pointee = pointer.Pointee.Desugar(); - - if (pointee is FunctionType) - { - var function = pointee as FunctionType; - return string.Format("{0}^", function.Visit(this, quals)); - } - - if (pointee.IsPrimitiveType(PrimitiveType.Char) && quals.IsConst) - { - return "System::String^"; - } - - PrimitiveType primitive; - if (pointee.IsPrimitiveType(out primitive)) - { - var param = Context.Parameter; - if (param != null && (param.IsOut || param.IsInOut)) - return VisitPrimitiveType(primitive); - - return VisitPrimitiveType(primitive, quals) + "*"; - } - - Enumeration @enum; - if (pointee.IsTagDecl(out @enum)) - { - var typeName = @enum.Visit(this); - return string.Format("{0}*", typeName); - } - - return pointee.Visit(this, quals); - } - - public string VisitMemberPointerType(MemberPointerType member, - TypeQualifiers quals) - { - throw new NotImplementedException(); - } - - public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals) - { - return VisitPrimitiveType(builtin.Type); - } - - public string VisitPrimitiveType(PrimitiveType primitive) - { - switch (primitive) - { - case PrimitiveType.Bool: return "bool"; - case PrimitiveType.Void: return "void"; - case PrimitiveType.Char16: - case PrimitiveType.WideChar: return "System::Char"; - case PrimitiveType.Int8: return Options.MarshalCharAsManagedChar ? "System::Char" : "char"; - case PrimitiveType.UInt8: return "unsigned char"; - case PrimitiveType.Int16: return "short"; - case PrimitiveType.UInt16: return "unsigned short"; - case PrimitiveType.Int32: return "int"; - case PrimitiveType.UInt32: return "unsigned int"; - case PrimitiveType.Int64: return "long long"; - case PrimitiveType.UInt64: return "unsigned long long"; - case PrimitiveType.Float: return "float"; - case PrimitiveType.Double: return "double"; - case PrimitiveType.IntPtr: return "IntPtr"; - case PrimitiveType.UIntPtr: return "UIntPtr"; - } - - throw new NotSupportedException(); - } - - public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals) - { - var decl = typedef.Declaration; - - TypeMap typeMap = null; - if (TypeMapDatabase.FindTypeMap(decl, out typeMap)) - { - typeMap.Type = typedef; - Context.Type = typedef; - return typeMap.CLISignature(Context); - } - - FunctionType func; - if (decl.Type.IsPointerTo(out func)) - { - // TODO: Use SafeIdentifier() - return string.Format("{0}^", VisitDeclaration(decl)); - } - - return decl.Type.Visit(this); - } - - public string VisitAttributedType(AttributedType attributed, TypeQualifiers quals) - { - return attributed.Modified.Visit(this); - } - - public string VisitDecayedType(DecayedType decayed, TypeQualifiers quals) - { - return decayed.Decayed.Visit(this); - } - - public string VisitTemplateSpecializationType(TemplateSpecializationType template, - TypeQualifiers quals) - { - var decl = template.Template.TemplatedDecl; - - TypeMap typeMap = null; - if (TypeMapDatabase.FindTypeMap(template, out typeMap)) - { - typeMap.Declaration = decl; - typeMap.Type = template; - Context.Type = template; - return typeMap.CLISignature(Context); - } - - return decl.Name; - } - - public string VisitTemplateParameterType(TemplateParameterType param, - TypeQualifiers quals) - { - return param.Parameter.Name; - } - - public string VisitTemplateParameterSubstitutionType( - TemplateParameterSubstitutionType param, TypeQualifiers quals) - { - throw new NotImplementedException(); - } - - public string VisitInjectedClassNameType(InjectedClassNameType injected, TypeQualifiers quals) - { - throw new NotImplementedException(); - } - - public string VisitDependentNameType(DependentNameType dependent, TypeQualifiers quals) - { - throw new NotImplementedException(); - } - - public string VisitPackExpansionType(PackExpansionType packExpansionType, TypeQualifiers quals) - { - return string.Empty; - } - - public string VisitCILType(CILType type, TypeQualifiers quals) - { - return type.Type.FullName.Replace(".", "::") + "^"; - } - - public string VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) - { - return VisitPrimitiveType(type); - } - - public string VisitDeclaration(Declaration decl, TypeQualifiers quals) - { - return VisitDeclaration(decl); - } - - public string VisitDeclaration(Declaration decl) - { - var names = new List(); - - if (Options.GenerateLibraryNamespace) - names.Add(Driver.Options.OutputNamespace); - - if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName)) - names.Add(decl.Namespace.QualifiedName); - - names.Add(decl.Visit(this)); - - return string.Join("::", names); - } - - public string VisitClassDecl(Class @class) - { - if (@class.CompleteDeclaration != null) - return VisitClassDecl(@class.CompleteDeclaration as Class); - - return string.Format("{0}{1}", @class.Name, @class.IsRefType ? "^" - : string.Empty); - } - - public string VisitFieldDecl(Field field) - { - throw new NotImplementedException(); - } - - public string VisitFunctionDecl(Function function) - { - throw new NotImplementedException(); - } - - public string VisitMethodDecl(Method method) - { - throw new NotImplementedException(); - } - - public string VisitParameterDecl(Parameter parameter) - { - throw new NotImplementedException(); - } - - public string VisitTypedefDecl(TypedefDecl typedef) - { - return typedef.Name; - } - - public string VisitEnumDecl(Enumeration @enum) - { - return @enum.Name; - } - - public string VisitVariableDecl(Variable variable) - { - throw new NotImplementedException(); - } - - public string VisitClassTemplateDecl(ClassTemplate template) - { - throw new NotImplementedException(); - } - - public string VisitFunctionTemplateDecl(FunctionTemplate template) - { - throw new NotImplementedException(); - } - - public string VisitMacroDefinition(MacroDefinition macro) - { - throw new NotImplementedException(); - } - - public string VisitNamespace(Namespace @namespace) - { - throw new NotImplementedException(); - } - - public string VisitEvent(Event @event) - { - throw new NotImplementedException(); - } - - public string VisitProperty(Property property) - { - throw new NotImplementedException(); - } - - public string ToString(Type type) - { - return type.Visit(this); - } - } -} +using System; +using System.Collections.Generic; +using CppSharp.AST; +using CppSharp.AST.Extensions; +using CppSharp.Types; +using Type = CppSharp.AST.Type; + +namespace CppSharp.Generators.CLI +{ + public class CLITypePrinterContext : TypePrinterContext + { + public CLITypePrinterContext() + { + + } + + public CLITypePrinterContext(TypePrinterContextKind kind) + : base(kind) + { + } + } + + public class CLITypePrinter : ITypePrinter, IDeclVisitor + { + public Driver Driver { get; set; } + public CLITypePrinterContext Context { get; set; } + + readonly ITypeMapDatabase TypeMapDatabase; + readonly DriverOptions Options; + + public CLITypePrinter(Driver driver) + { + Driver = driver; + TypeMapDatabase = driver.TypeDatabase; + Options = driver.Options; + Context = new CLITypePrinterContext(); + } + + public CLITypePrinter(Driver driver, CLITypePrinterContext context) + : this(driver) + { + Context = context; + } + + public string VisitTagType(TagType tag, TypeQualifiers quals) + { + TypeMap typeMap = null; + if (TypeMapDatabase.FindTypeMap(tag, out typeMap)) + { + typeMap.Type = tag; + Context.Type = tag; + return typeMap.CLISignature(Context); + } + + Declaration decl = tag.Declaration; + + if (decl == null) + return string.Empty; + + return VisitDeclaration(decl, quals); + } + + public string VisitArrayType(ArrayType array, TypeQualifiers quals) + { + return string.Format("cli::array<{0}>^", array.Type.Visit(this)); + } + + public string VisitFunctionType(FunctionType function, TypeQualifiers quals) + { + var arguments = function.Parameters; + var returnType = function.ReturnType; + var args = string.Empty; + + if (arguments.Count > 0) + args = VisitParameters(function.Parameters, hasNames: false); + + if (returnType.Type.IsPrimitiveType(PrimitiveType.Void)) + { + if (!string.IsNullOrEmpty(args)) + args = string.Format("<{0}>", args); + return string.Format("System::Action{0}", args); + } + + if (!string.IsNullOrEmpty(args)) + args = string.Format(", {0}", args); + + return string.Format("System::Func<{0}{1}>", returnType.Visit(this), args); + } + + public string VisitParameters(IEnumerable @params, + bool hasNames) + { + var args = new List(); + + foreach (var param in @params) + args.Add(VisitParameter(param, hasNames)); + + return string.Join(", ", args); + } + + public string VisitParameter(Parameter param, bool hasName = true) + { + Context.Parameter = param; + var type = param.Type.Visit(this, param.QualifiedType.Qualifiers); + Context.Parameter = null; + + var str = string.Empty; + if(param.Usage == ParameterUsage.Out) + str += "[System::Runtime::InteropServices::Out] "; + + str += type; + + if(param.Usage == ParameterUsage.Out || + param.Usage == ParameterUsage.InOut) + str += "%"; + + if (hasName && !string.IsNullOrEmpty(param.Name)) + str += " " + param.Name; + + return str; + } + + public string VisitDelegate(FunctionType function) + { + return string.Format("delegate {0} {{0}}({1})", + function.ReturnType.Visit(this), + VisitParameters(function.Parameters, hasNames: true)); + } + + public string VisitPointerType(PointerType pointer, TypeQualifiers quals) + { + var pointee = pointer.Pointee.Desugar(); + + if (pointee is FunctionType) + { + var function = pointee as FunctionType; + return string.Format("{0}^", function.Visit(this, quals)); + } + + if (pointee.IsPrimitiveType(PrimitiveType.Char) && quals.IsConst) + { + return "System::String^"; + } + + // From http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx + // Any of the following types may be a pointer type: + // * sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool. + // * Any enum type. + // * Any pointer type. + // * Any user-defined struct type that contains fields of unmanaged types only. + var finalPointee = pointer.GetFinalPointee(); + if (finalPointee.IsPrimitiveType()) + { + // Skip one indirection if passed by reference + var param = Context.Parameter; + if (param != null && (param.IsOut || param.IsInOut) + && pointee == finalPointee) + return pointee.Visit(this, quals); + + return pointee.Visit(this, quals) + "*"; + } + + Enumeration @enum; + if (pointee.IsTagDecl(out @enum)) + { + var typeName = @enum.Visit(this); + return string.Format("{0}*", typeName); + } + + return pointee.Visit(this, quals); + } + + public string VisitMemberPointerType(MemberPointerType member, + TypeQualifiers quals) + { + throw new NotImplementedException(); + } + + public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals) + { + return VisitPrimitiveType(builtin.Type); + } + + public string VisitPrimitiveType(PrimitiveType primitive) + { + switch (primitive) + { + case PrimitiveType.Bool: return "bool"; + case PrimitiveType.Void: return "void"; + case PrimitiveType.Char16: + case PrimitiveType.WideChar: return "System::Char"; + case PrimitiveType.Int8: return Options.MarshalCharAsManagedChar ? "System::Char" : "char"; + case PrimitiveType.UInt8: return "unsigned char"; + case PrimitiveType.Int16: return "short"; + case PrimitiveType.UInt16: return "unsigned short"; + case PrimitiveType.Int32: return "int"; + case PrimitiveType.UInt32: return "unsigned int"; + case PrimitiveType.Int64: return "long long"; + case PrimitiveType.UInt64: return "unsigned long long"; + case PrimitiveType.Float: return "float"; + case PrimitiveType.Double: return "double"; + case PrimitiveType.IntPtr: return "IntPtr"; + case PrimitiveType.UIntPtr: return "UIntPtr"; + } + + throw new NotSupportedException(); + } + + public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals) + { + var decl = typedef.Declaration; + + TypeMap typeMap = null; + if (TypeMapDatabase.FindTypeMap(decl, out typeMap)) + { + typeMap.Type = typedef; + Context.Type = typedef; + return typeMap.CLISignature(Context); + } + + FunctionType func; + if (decl.Type.IsPointerTo(out func)) + { + // TODO: Use SafeIdentifier() + return string.Format("{0}^", VisitDeclaration(decl)); + } + + return decl.Type.Visit(this); + } + + public string VisitAttributedType(AttributedType attributed, TypeQualifiers quals) + { + return attributed.Modified.Visit(this); + } + + public string VisitDecayedType(DecayedType decayed, TypeQualifiers quals) + { + return decayed.Decayed.Visit(this); + } + + public string VisitTemplateSpecializationType(TemplateSpecializationType template, + TypeQualifiers quals) + { + var decl = template.Template.TemplatedDecl; + + TypeMap typeMap = null; + if (TypeMapDatabase.FindTypeMap(template, out typeMap)) + { + typeMap.Declaration = decl; + typeMap.Type = template; + Context.Type = template; + return typeMap.CLISignature(Context); + } + + return decl.Name; + } + + public string VisitTemplateParameterType(TemplateParameterType param, + TypeQualifiers quals) + { + return param.Parameter.Name; + } + + public string VisitTemplateParameterSubstitutionType( + TemplateParameterSubstitutionType param, TypeQualifiers quals) + { + throw new NotImplementedException(); + } + + public string VisitInjectedClassNameType(InjectedClassNameType injected, TypeQualifiers quals) + { + throw new NotImplementedException(); + } + + public string VisitDependentNameType(DependentNameType dependent, TypeQualifiers quals) + { + throw new NotImplementedException(); + } + + public string VisitPackExpansionType(PackExpansionType packExpansionType, TypeQualifiers quals) + { + return string.Empty; + } + + public string VisitCILType(CILType type, TypeQualifiers quals) + { + return type.Type.FullName.Replace(".", "::") + "^"; + } + + public string VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) + { + return VisitPrimitiveType(type); + } + + public string VisitDeclaration(Declaration decl, TypeQualifiers quals) + { + return VisitDeclaration(decl); + } + + public string VisitDeclaration(Declaration decl) + { + var names = new List(); + + if (Options.GenerateLibraryNamespace) + names.Add(Driver.Options.OutputNamespace); + + if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName)) + names.Add(decl.Namespace.QualifiedName); + + names.Add(decl.Visit(this)); + + return string.Join("::", names); + } + + public string VisitClassDecl(Class @class) + { + if (@class.CompleteDeclaration != null) + return VisitClassDecl(@class.CompleteDeclaration as Class); + + return string.Format("{0}{1}", @class.Name, @class.IsRefType ? "^" + : string.Empty); + } + + public string VisitFieldDecl(Field field) + { + throw new NotImplementedException(); + } + + public string VisitFunctionDecl(Function function) + { + throw new NotImplementedException(); + } + + public string VisitMethodDecl(Method method) + { + throw new NotImplementedException(); + } + + public string VisitParameterDecl(Parameter parameter) + { + throw new NotImplementedException(); + } + + public string VisitTypedefDecl(TypedefDecl typedef) + { + return typedef.Name; + } + + public string VisitEnumDecl(Enumeration @enum) + { + return @enum.Name; + } + + public string VisitVariableDecl(Variable variable) + { + throw new NotImplementedException(); + } + + public string VisitClassTemplateDecl(ClassTemplate template) + { + throw new NotImplementedException(); + } + + public string VisitFunctionTemplateDecl(FunctionTemplate template) + { + throw new NotImplementedException(); + } + + public string VisitMacroDefinition(MacroDefinition macro) + { + throw new NotImplementedException(); + } + + public string VisitNamespace(Namespace @namespace) + { + throw new NotImplementedException(); + } + + public string VisitEvent(Event @event) + { + throw new NotImplementedException(); + } + + public string VisitProperty(Property property) + { + throw new NotImplementedException(); + } + + public string ToString(Type type) + { + return type.Visit(this); + } + } +} diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index c5aaebc4..52e2fe6c 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -2105,7 +2105,7 @@ namespace CppSharp.Generators.CSharp if (Driver.Options.MarshalCharAsManagedChar) { foreach (var param in method.Parameters.Where( - p => p.Type.Desugar().IsPrimitiveType(PrimitiveType.Int8))) + p => p.Type.IsPrimitiveType(PrimitiveType.Int8))) { WriteLine("if ({0} < char.MinValue || {0} > sbyte.MaxValue)", param.Name); WriteLineIndent( @@ -2690,7 +2690,7 @@ namespace CppSharp.Generators.CSharp WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled); - if (function.ReturnType.Type.Desugar().IsPrimitiveType(PrimitiveType.Bool)) + if (function.ReturnType.Type.IsPrimitiveType(PrimitiveType.Bool)) WriteLine("[return: MarshalAsAttribute(UnmanagedType.I1)]"); var @params = new List(); diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index df979a9e..fdfde8c0 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -208,18 +208,27 @@ namespace CppSharp.Generators.CSharp if (IsConstCharString(pointer)) return isManagedContext ? "string" : "global::System.IntPtr"; - PrimitiveType primitive; var desugared = pointee.Desugar(); - if (desugared.IsPrimitiveType(out primitive)) + + // From http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx + // Any of the following types may be a pointer type: + // * sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool. + // * Any enum type. + // * Any pointer type. + // * Any user-defined struct type that contains fields of unmanaged types only. + var finalPointee = pointer.GetFinalPointee(); + if (finalPointee.IsPrimitiveType()) { - if (isManagedContext && Context.Parameter != null && - (Context.Parameter.IsOut || Context.Parameter.IsInOut)) - return VisitPrimitiveType(primitive, quals); + // Skip one indirection if passed by reference + var param = Context.Parameter; + if (isManagedContext && param != null && (param.IsOut || param.IsInOut) + && pointee == finalPointee) + return pointee.Visit(this, quals); if (ContextKind == CSharpTypePrinterContextKind.GenericDelegate) return "global::System.IntPtr"; - return VisitPrimitiveType(primitive, quals) + "*"; + return pointee.Visit(this, quals) + "*"; } Enumeration @enum; diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index fc90c237..1d200420 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -342,7 +342,7 @@ namespace CppSharp.Passes var arrayType = type as ArrayType; PrimitiveType primitive; if (arrayType != null && arrayType.SizeType == ArrayType.ArraySize.Constant && - !arrayType.Type.Desugar().IsPrimitiveType(out primitive) && + !arrayType.Type.IsPrimitiveType(out primitive) && !arrayType.Type.Desugar().IsPointerToPrimitiveType()) { msg = "unsupported"; diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs index 841bcd5b..22564dd6 100644 --- a/src/Generator/Passes/CheckOperatorsOverloads.cs +++ b/src/Generator/Passes/CheckOperatorsOverloads.cs @@ -100,14 +100,18 @@ namespace CppSharp.Passes if (!@operator.ReturnType.Qualifiers.IsConst && @operator.ReturnType.Type.IsAddress()) property.SetMethod = @operator; - // C++/CLI uses "default" as the indexer property name. if (Driver.Options.IsCLIGenerator) + { + // If we've a setter use the pointee as the type of the property. + var pointerType = property.Type as PointerType; + if (pointerType != null && property.HasSetter) + { + property.QualifiedType = new QualifiedType(pointerType.Pointee, property.QualifiedType.Qualifiers); + property.GetMethod.ReturnType = property.QualifiedType; + } + // C++/CLI uses "default" as the indexer property name. property.Name = "default"; - - property.GetMethod.Parameters[0].Name = "index"; - - if (property.SetMethod != null) - property.SetMethod.Parameters[0].Name = "index"; + } property.Parameters.AddRange(@operator.Parameters); diff --git a/src/Generator/Types/Types.cs b/src/Generator/Types/Types.cs index 3549fb63..8d1393d9 100644 --- a/src/Generator/Types/Types.cs +++ b/src/Generator/Types/Types.cs @@ -127,6 +127,17 @@ namespace CppSharp Ignore(); return base.VisitTemplateSpecializationType(template, quals); + } + + public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals) + { + // We don't know how to marshal non-static member functions + if (function.CallingConvention == CallingConvention.ThisCall) + { + Ignore(); + return false; + } + return base.VisitFunctionType(function, quals); } } diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index e65c1c79..68f4eaf6 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -22,7 +22,17 @@ public class BasicTests : GeneratorTestFixture Assert.That(hello.AddFoo(foo), Is.EqualTo(11)); Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11)); Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11)); - Assert.That(hello.AddFooRef(foo), Is.EqualTo(11)); + Assert.That(hello.AddFooRef(foo), Is.EqualTo(11)); + unsafe + { + var pointer = foo.SomePointer; + var pointerPointer = foo.SomePointerPointer; + for (int i = 0; i < 4; i++) + { + Assert.AreEqual(i, pointer[i]); + Assert.AreEqual(i, (*pointerPointer)[i]); + } + } var bar = new Bar { A = 4, B = 7 }; Assert.That(hello.AddBar(bar), Is.EqualTo(11)); @@ -166,6 +176,13 @@ public class BasicTests : GeneratorTestFixture var delegates = new TestDelegates(); var doubleSum = delegates.A(2) + delegates.B(2); Assert.AreEqual(8, doubleSum); + } + + [Test] + public void TestAttributedDelegate() + { + var result = basic.AttributedDelegate(2); + Assert.AreEqual(4, result); } [Test] @@ -223,7 +240,10 @@ public class BasicTests : GeneratorTestFixture public unsafe void TestIndexers() { var someStruct = new SomeStruct(); - Assert.That(someStruct[0], Is.EqualTo(1)); + Assert.That(someStruct[0], Is.EqualTo(1)); + Assert.That(someStruct["foo"], Is.EqualTo(1)); + someStruct[0] = 2; + Assert.That(someStruct[0], Is.EqualTo(2)); } [Test] diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index 54237caf..15fd7369 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -2,6 +2,11 @@ Foo::Foo() { + auto p = new int[4]; + for (int i = 0; i < 4; i++) + p[i] = i; + SomePointer = p; + SomePointerPointer = &SomePointer; } const char* Foo::GetANSI() diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 28689517..c31af1da 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -18,7 +18,11 @@ public: // TODO: VC++ does not support char16 // char16 chr16; - float nested_array[2][2]; + // Not properly handled yet - ignore + float nested_array[2][2]; + // Primitive pointer types + const int* SomePointer; + const int** SomePointerPointer; }; struct DLL_API Bar @@ -243,14 +247,26 @@ typedef int (*DelegateInGlobalNamespace)(int); struct DLL_API TestDelegates { typedef int (*DelegateInClass)(int); + typedef int(TestDelegates::*MemberDelegate)(int); - TestDelegates() : A(Double), B(Double) {} + TestDelegates() : A(Double), B(Double) { C = &TestDelegates::Triple; } static int Double(int N) { return N * 2; } + int Triple(int N) { return N * 3; } DelegateInClass A; DelegateInGlobalNamespace B; + // As long as we can't marshal them make sure they're ignored + MemberDelegate C; }; +// Tests delegate generation for attributed function types +typedef int(__cdecl *AttributedDelegate)(int n); +DLL_API int __cdecl Double(int n) { return n * 2; } +DLL_API AttributedDelegate GetAttributedDelegate() +{ + return Double; +} + // Tests memory leaks in constructors // C#: Marshal.FreeHGlobal(arg0); struct DLL_API TestMemoryLeaks @@ -307,8 +323,9 @@ typedef unsigned long foo_t; typedef struct DLL_API SomeStruct { SomeStruct() : p(1) {} - const foo_t& operator[](int i) const { return p; } - foo_t operator[](int i) { return p; } + foo_t& operator[](int i) { return p; } + // CSharp backend can't deal with a setter here + foo_t operator[](const char* name) { return p; } foo_t p; } SomeStruct; @@ -368,4 +385,4 @@ struct DLL_API TestGetterSetterToProperties { int getWidth() { return 640; } int getHeight() { return 480; } -}; \ No newline at end of file +};