private void DistributeMethod(Method method) { Type returnType = method.OriginalReturnType.Type.Desugar(); if ((returnType.IsPrimitiveType(PrimitiveType.Void) || returnType.IsPrimitiveType(PrimitiveType.Bool)) && method.Parameters.Any(p => p.Kind == ParameterKind.Regular)) { if (method.Parameters.Count == 1) { setters.Add(method); } else if (method.Parameters.Count > 1) { setMethods.Add(method); } } else { if (method.ConvertToProperty || IsGetter(method)) { getters.Add(method); } if (method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType)) { nonSetters.Add(method); } } }
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals) { if (!VisitType(pointer, quals)) { return(false); } var pointee = pointer.Pointee; Type type = pointee.Desugar(); if ((type.IsPrimitiveType(PrimitiveType.Char) || type.IsPrimitiveType(PrimitiveType.WideChar)) && pointer.QualifiedPointee.Qualifiers.IsConst) { Context.Return.Write("Marshal.StringToHGlobalAnsi({0})", Helpers.SafeIdentifier(Context.Parameter.Name)); CSharpContext.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Helpers.SafeIdentifier(Context.ArgName)); return(true); } if (pointee is FunctionType) { var function = pointee as FunctionType; return(VisitDelegateType(function, function.ToString())); } Class @class; if (type.IsTagDecl(out @class) && @class.IsValueType) { if (Context.Parameter.Usage == ParameterUsage.Out) { Context.SupportBefore.WriteLine("var {0} = new {1}.Internal();", Generator.GeneratedIdentifier(Context.ArgName), @class.Name); } else { Context.SupportBefore.WriteLine("var {0} = {1}.ToInternal();", Generator.GeneratedIdentifier(Context.ArgName), Helpers.SafeIdentifier(Context.Parameter.Name)); } Context.Return.Write("new global::System.IntPtr(&{0})", Generator.GeneratedIdentifier(Context.ArgName)); return(true); } PrimitiveType primitive; if (type.IsPrimitiveType(out primitive)) { Context.Return.Write(Context.Parameter.Name); return(true); } return(pointee.Visit(this, quals)); }
private static bool IsSetter(Method method) { Type returnType = method.OriginalReturnType.Type.Desugar(); return((returnType.IsPrimitiveType(PrimitiveType.Void) || returnType.IsPrimitiveType(PrimitiveType.Bool)) && method.Parameters.Count(p => p.Kind == ParameterKind.Regular) == 1); }
private void MarshalVariableArray(Type arrayType) { if (arrayType.IsPrimitiveType()) { Context.Return.Write(Context.Parameter.Name); return; } var intermediateArray = $"__{Context.Parameter.Name}"; var intermediateArrayType = typePrinter.PrintNative(arrayType); const string intPtrType = CSharpTypePrinter.IntPtrType; Context.Before.WriteLine($"{intermediateArrayType}[] {intermediateArray};"); Context.Before.WriteLine($"if (ReferenceEquals({Context.Parameter.Name}, null))"); Context.Before.WriteLineIndent($"{intermediateArray} = new[] {{ {intPtrType}.Zero }};"); Context.Before.WriteLine("else"); Context.Before.WriteStartBraceIndent(); Context.Before.WriteLine($@"{intermediateArray} = new { intermediateArrayType}[{Context.Parameter.Name}.Length];"); Context.Before.WriteLine($"for (int i = 0; i < {intermediateArray}.Length; i++)"); Context.Before.WriteStartBraceIndent(); const string element = "__element"; Context.Before.WriteLine($"var {element} = {Context.Parameter.Name}[i];"); Context.Before.WriteLine($@"{intermediateArray}[i] = ReferenceEquals({ element}, null) ? {intPtrType}.Zero : {element}.{Helpers.InstanceIdentifier};"); Context.Before.WriteCloseBraceIndent(); Context.Before.WriteCloseBraceIndent(); Context.Return.Write(intermediateArray); }
private static bool CheckForEnumValue(Parameter parameter, Type desugared) { var enumItem = parameter.DefaultArgument.Declaration as Enumeration.Item; if (enumItem != null) { parameter.DefaultArgument.String = string.Format("{0}{1}{2}.{3}", desugared.IsPrimitiveType() ? "(int) " : string.Empty, string.IsNullOrEmpty(enumItem.Namespace.Namespace.Name) ? string.Empty : enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name); return true; } var call = parameter.DefaultArgument.Declaration as Function; if (call != null || parameter.DefaultArgument.Class == StatementClass.BinaryOperator) { string @params = regexFunctionParams.Match(parameter.DefaultArgument.String).Groups[1].Value; if (@params.Contains("::")) parameter.DefaultArgument.String = regexDoubleColon.Replace(@params, desugared + "."); else parameter.DefaultArgument.String = regexName.Replace(@params, desugared + ".$1"); return true; } return false; }
private static bool CheckForEnumValue(Parameter parameter, Type desugared) { var enumItem = parameter.DefaultArgument.Declaration as Enumeration.Item; if (enumItem != null) { parameter.DefaultArgument.String = string.Format("{0}{1}.{2}.{3}", desugared.IsPrimitiveType() ? "(int) " : string.Empty, enumItem.Namespace.Namespace.Name, enumItem.Namespace.Name, enumItem.Name); return(true); } var call = parameter.DefaultArgument.Declaration as Method; if (call != null && call.IsConstructor) { string @params = regexFunctionParams.Match(parameter.DefaultArgument.String).Groups[1].Value; if (@params.Contains("::")) { parameter.DefaultArgument.String = regexDoubleColon.Replace(@params, desugared + "."); } else { parameter.DefaultArgument.String = regexName.Replace(@params, desugared + ".$1"); } return(true); } return(false); }
private void CheckForDefaultEmptyChar(Parameter parameter, Type desugared) { if (parameter.DefaultArgument.String == "0" && Driver.Options.MarshalCharAsManagedChar && desugared.IsPrimitiveType(PrimitiveType.Char)) { parameter.DefaultArgument.String = "'\\0'"; } }
private static bool IsSupportedArray(Type typeInArray) { if (typeInArray.IsPrimitiveType()) { // no need to unwrap, as it is legal to have fixed arrays of primitive types (in C# pinvoke) return(true); } return(false); }
private static void CheckForULongValue(Parameter parameter, Type desugared) { ulong value; string @default = parameter.DefaultArgument.String; // HACK: .NET's Parse/TryParse have a bug preventing them from parsing UL-suffixed ulongs if (desugared.IsPrimitiveType() && @default.EndsWith("UL")) { @default = @default.Substring(0, @default.Length - 2); } if (ulong.TryParse(@default, out value)) { parameter.DefaultArgument.String = value.ToString(CultureInfo.InvariantCulture); } }
private void MarshalArray(ArrayType array) { Type arrayType = array.Type.Desugar(); if (arrayType.IsPrimitiveType() || arrayType.IsPointerToPrimitiveType() || Context.MarshalKind != MarshalKind.GenericDelegate) { Context.Return.Write(Context.ReturnVarName); return; } var intermediateArray = Generator.GeneratedIdentifier(Context.ReturnVarName); var intermediateArrayType = arrayType.Visit(typePrinter); Context.Before.WriteLine($"{intermediateArrayType}[] {intermediateArray};"); Context.Before.WriteLine($"if (ReferenceEquals({Context.ReturnVarName}, null))"); Context.Before.WriteLineIndent($"{intermediateArray} = null;"); Context.Before.WriteLine("else"); Context.Before.WriteStartBraceIndent(); Context.Before.WriteLine($@"{intermediateArray} = new { intermediateArrayType}[{Context.ReturnVarName}.Length];"); Context.Before.WriteLine($"for (int i = 0; i < {intermediateArray}.Length; i++)"); if (arrayType.IsAddress()) { Context.Before.WriteStartBraceIndent(); string element = Generator.GeneratedIdentifier("element"); Context.Before.WriteLine($"var {element} = {Context.ReturnVarName}[i];"); var intPtrZero = $"{CSharpTypePrinter.IntPtrType}.Zero"; Context.Before.WriteLine($@"{intermediateArray}[i] = {element} == { intPtrZero} ? null : {intermediateArrayType}.{ Helpers.CreateInstanceIdentifier}({element});"); Context.Before.WriteCloseBraceIndent(); } else { Context.Before.WriteLineIndent($@"{intermediateArray}[i] = { intermediateArrayType}.{Helpers.CreateInstanceIdentifier}({ Context.ReturnVarName}[i]);"); } Context.Before.WriteCloseBraceIndent(); Context.Return.Write(intermediateArray); }
private static bool CheckForEnumValue(Expression arg, Type desugared) { var enumItem = arg.Declaration as Enumeration.Item; if (enumItem != null) { arg.String = string.Format("{0}{1}{2}.{3}", desugared.IsPrimitiveType() ? "(int) " : string.Empty, string.IsNullOrEmpty(enumItem.Namespace.Namespace.Name) ? string.Empty : enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name); return true; } var call = arg.Declaration as Function; if ((call != null || arg.Class == StatementClass.BinaryOperator) && arg.String != "0") { string @params = regexFunctionParams.Match(arg.String).Groups[1].Value; TranslateEnumExpression(arg, desugared, @params); return true; } return false; }
private static bool CheckForEnumValue(Expression arg, Type desugared) { var enumItem = arg.Declaration as Enumeration.Item; if (enumItem != null) { arg.String = string.Format("{0}{1}{2}.{3}", desugared.IsPrimitiveType() ? "(int) " : string.Empty, string.IsNullOrEmpty(enumItem.Namespace.Namespace.Name) ? string.Empty : enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name); return(true); } var call = arg.Declaration as Function; if ((call != null || arg.Class == StatementClass.BinaryOperator) && arg.String != "0") { string @params = regexFunctionParams.Match(arg.String).Groups[1].Value; TranslateEnumExpression(arg, desugared, @params); return(true); } return(false); }
public override TypePrinterResult VisitArrayType(ArrayType array, TypeQualifiers quals) { Type arrayType = array.Type.Desugar(); if ((MarshalKind == MarshalKind.NativeField || (ContextKind == TypePrinterContextKind.Native && MarshalKind == MarshalKind.ReturnVariableArray)) && array.SizeType == ArrayType.ArraySize.Constant) { if (array.Size == 0) { var pointer = new PointerType(array.QualifiedType); return(pointer.Visit(this)); } PrimitiveType primitiveType; if ((arrayType.IsPointerToPrimitiveType(out primitiveType) && !(arrayType is FunctionType)) || (arrayType.IsPrimitiveType() && MarshalKind != MarshalKind.NativeField)) { if (primitiveType == PrimitiveType.Void) { return("void*"); } return(array.QualifiedType.Visit(this)); } if (Parameter != null) { return(IntPtrType); } Enumeration @enum; if (arrayType.TryGetEnum(out @enum)) { return(new TypePrinterResult { Type = $"fixed {@enum.BuiltinType}", NameSuffix = $"[{array.Size}]" }); } Class @class; if (arrayType.TryGetClass(out @class)) { return(new TypePrinterResult { Type = "fixed byte", NameSuffix = $"[{array.Size * @class.Layout.Size}]" }); } var arrayElemType = array.QualifiedType.Visit(this).ToString(); // C# does not support fixed arrays of machine pointer type (void* or IntPtr). // In that case, replace it by a pointer to an integer type of the same size. if (arrayElemType == IntPtrType) { arrayElemType = Context.TargetInfo.PointerWidth == 64 ? "long" : "int"; } // Do not write the fixed keyword multiple times for nested array types var fixedKeyword = arrayType is ArrayType ? string.Empty : "fixed "; return(new TypePrinterResult { Type = $"{fixedKeyword}{arrayElemType}", NameSuffix = $"[{array.Size}]" }); } // const char* and const char[] are the same so we can use a string if (array.SizeType == ArrayType.ArraySize.Incomplete && arrayType.IsPrimitiveType(PrimitiveType.Char) && array.QualifiedType.Qualifiers.IsConst) { return("string"); } if (arrayType.IsPointerToPrimitiveType(PrimitiveType.Char)) { var prefix = ContextKind == TypePrinterContextKind.Managed ? string.Empty : "[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] "; return($"{prefix}string[]"); } var arraySuffix = array.SizeType != ArrayType.ArraySize.Constant && MarshalKind == MarshalKind.ReturnVariableArray ? (ContextKind == TypePrinterContextKind.Managed && arrayType.IsPrimitiveType() ? "*" : string.Empty) : "[]"; return($"{arrayType.Visit(this)}{arraySuffix}"); }
public bool FindTypeMap(Type type, out TypeMap typeMap) { if (typeMaps.ContainsKey(type)) { typeMap = typeMaps[type]; return(typeMap.IsEnabled); } var template = type as TemplateSpecializationType; if (template != null) { var specialization = template.GetClassTemplateSpecialization(); if (specialization != null && FindTypeMap(specialization, out typeMap)) { return(true); } if (template.Template.TemplatedDecl != null) { if (FindTypeMap(template.Template.TemplatedDecl, out typeMap)) { typeMap.Type = type; return(true); } return(false); } } Type desugared = type.Desugar(); desugared = (desugared.GetFinalPointee() ?? desugared).Desugar(); bool printExtra = desugared.IsPrimitiveType() || (desugared.GetFinalPointee() ?? desugared).Desugar().IsPrimitiveType(); var typePrinter = new CppTypePrinter { PrintTypeQualifiers = printExtra, PrintTypeModifiers = printExtra, PrintLogicalNames = true }; foreach (var resolveTypeDefs in new[] { true, false }) { foreach (var typePrintScopeKind in new[] { TypePrintScopeKind.Local, TypePrintScopeKind.Qualified }) { typePrinter.ResolveTypedefs = resolveTypeDefs; typePrinter.ScopeKind = typePrintScopeKind; if (FindTypeMap(type.Visit(typePrinter), out typeMap)) { typeMap.Type = type; typeMaps[type] = typeMap; return(true); } } } typeMap = null; var typedef = type as TypedefType; return(typedef != null && FindTypeMap(typedef.Declaration.Type, out typeMap)); }
private UnwrapInfo?GetUnwrapInfo(ArrayType arrayType, Type typeInArray) { long unwrapCount; Type unwrapType; // in bits long unwrapTypeWidth; if (typeInArray.IsPointerToPrimitiveType()) { // need to unwrap if field is array of pointer to primitive type // int* A[N] // becomes // int* A_0; // int* A_N; // unwrap to multiple pointer fields unwrapType = new PointerType { QualifiedPointee = ((PointerType)typeInArray).QualifiedPointee }; unwrapCount = arrayType.Size; // TODO: get type width from driver TargetInfo! unwrapTypeWidth = 0; } else if (typeInArray.IsPointerToArrayType()) { // need to unwrap if field is array of pointer to array // A (*int[N])[M] // becomes // int** X_0; // int** X_M; var innerArray = (ArrayType)((PointerType)typeInArray).Pointee; unwrapType = new PointerType { QualifiedPointee = new QualifiedType(new PointerType { QualifiedPointee = new QualifiedType(innerArray.Type) }) }; unwrapCount = arrayType.Size; unwrapTypeWidth = Driver.TargetInfo.PointerWidth; } else if (typeInArray is ArrayType) { // need to unwrap if field is array of array // int A[N][M] // becomes // int A_0[M]; // int A_N[M]; Type innerArray = ((ArrayType)(typeInArray)).Type; unwrapType = new ArrayType { Size = ((ArrayType)(typeInArray)).Size, SizeType = ArrayType.ArraySize.Constant, Type = innerArray }; unwrapCount = arrayType.Size / ((ArrayType)(typeInArray)).Size; // TODO: get type width from driver TargetInfo! unwrapTypeWidth = 0; } else if (!typeInArray.IsPrimitiveType()) { // need tp unwrap if field is array of complex type // Struct A[N] // becomes // Struct A_0; // Struct A_N; unwrapType = typeInArray; unwrapCount = arrayType.Size; // TODO: get type width from driver TargetInfo! unwrapTypeWidth = 0; } else { return(null); } return(new UnwrapInfo { UnwrapType = unwrapType, UnwrapCount = unwrapCount, UnwrapTypeWidth = unwrapTypeWidth }); }
private static void CheckForULongValue(Parameter parameter, Type desugared) { ulong value; string @default = parameter.DefaultArgument.String; // HACK: .NET's Parse/TryParse have a bug preventing them from parsing UL-suffixed ulongs if (desugared.IsPrimitiveType() && @default.EndsWith("UL")) @default = @default.Substring(0, @default.Length - 2); if (ulong.TryParse(@default, out value)) parameter.DefaultArgument.String = value.ToString(CultureInfo.InvariantCulture); }
public bool FindTypeMap(Type type, out TypeMap typeMap) { // Looks up the type in the cache map. if (typeMaps.ContainsKey(type)) { typeMap = typeMaps[type]; typeMap.Type = type; return(typeMap.IsEnabled); } var template = type as TemplateSpecializationType; if (template != null) { var specialization = template.GetClassTemplateSpecialization(); if (specialization != null && FindTypeMap(specialization, out typeMap)) { return(true); } if (template.Template.TemplatedDecl != null) { if (FindTypeMap(template.Template.TemplatedDecl, out typeMap)) { typeMap.Type = type; return(true); } return(false); } } Type desugared = type.Desugar(); desugared = (desugared.GetFinalPointee() ?? desugared).Desugar(); bool printExtra = desugared.IsPrimitiveType() || (desugared.GetFinalPointee() ?? desugared).Desugar().IsPrimitiveType(); var typePrinter = new CppTypePrinter(Context) { ResolveTypeMaps = false, PrintTypeQualifiers = printExtra, PrintTypeModifiers = printExtra, PrintLogicalNames = true }; typePrinter.PushContext(TypePrinterContextKind.Native); foreach (var resolveTypeDefs in new[] { false, true }) { foreach (var typePrintScopeKind in new[] { TypePrintScopeKind.Local, TypePrintScopeKind.Qualified }) { typePrinter.ResolveTypedefs = resolveTypeDefs; typePrinter.PushScope(typePrintScopeKind); var typeName = type.Visit(typePrinter); typePrinter.PopScope(); if (FindTypeMap(typeName, out typeMap)) { typeMap.Type = type; typeMaps[type] = typeMap; return(true); } } } typeMap = null; return(false); }
public void GenerateFunctionCall(Function function, Class @class = null, Type publicRetType = null) { CheckArgumentRange(function); if (function.OperatorKind == CXXOperatorKind.EqualEqual || function.OperatorKind == CXXOperatorKind.ExclaimEqual) { WriteLine("bool {0}Null = ReferenceEquals({0}, nullptr);", function.Parameters[0].Name); WriteLine("bool {0}Null = ReferenceEquals({0}, nullptr);", function.Parameters[1].Name); WriteLine("if ({0}Null || {1}Null)", function.Parameters[0].Name, function.Parameters[1].Name); WriteLineIndent("return {0}{1}Null && {2}Null{3};", function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(", function.Parameters[0].Name, function.Parameters[1].Name, function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")"); } var retType = function.ReturnType; if (publicRetType == null) { publicRetType = retType.Type; } var needsReturn = !publicRetType.IsPrimitiveType(PrimitiveType.Void); const string valueMarshalName = "_this0"; var isValueType = @class != null && @class.IsValueType; if (isValueType && !IsNativeFunctionOrStaticMethod(function)) { WriteLine($"auto {valueMarshalName} = {typePrinter.PrintTag(@class)}::{@class.QualifiedOriginalName}();"); var param = new Parameter { Name = "(*this)", Namespace = function.Namespace }; var ctx = new MarshalContext(Context, CurrentIndentation) { Parameter = param }; ctx.VarPrefix.Write(valueMarshalName); var marshal = new CLIMarshalManagedToNativePrinter(ctx); marshal.MarshalValueClassProperties(@class, valueMarshalName); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) { Write(marshal.Context.Before); } } var @params = GenerateFunctionParamsMarshal(function.Parameters, function); var returnIdentifier = Helpers.ReturnIdentifier; if (needsReturn) { if (retType.Type.IsReference()) { Write("auto &{0} = ", returnIdentifier); } else { Write("auto {0} = ", returnIdentifier); } } if (function.OperatorKind == CXXOperatorKind.Conversion || function.OperatorKind == CXXOperatorKind.ExplicitConversion) { var method = function as Method; var typeName = method.ConversionType.Visit(new CppTypePrinter(Context)); WriteLine("({0}) {1};", typeName, @params[0].Name); } else if (function.IsOperator && function.OperatorKind != CXXOperatorKind.Subscript) { var opName = function.Name.Replace("operator", "").Trim(); switch (Operators.ClassifyOperator(function)) { case CXXOperatorArity.Unary: WriteLine("{0} {1};", opName, @params[0].Name); break; case CXXOperatorArity.Binary: WriteLine("{0} {1} {2};", @params[0].Name, opName, @params[1].Name); break; } } else { if (IsNativeFunctionOrStaticMethod(function)) { Write($"::{function.QualifiedOriginalName}("); } else { if (isValueType) { Write($"{valueMarshalName}."); } else if (IsNativeMethod(function)) { Write($"(({typePrinter.PrintTag(@class)}::{@class.QualifiedOriginalName}*)NativePtr)->"); } Write("{0}(", function.OriginalName); } GenerateFunctionParams(@params); WriteLine(");"); } foreach (var paramInfo in @params) { var param = paramInfo.Param; if (param.Usage != ParameterUsage.Out && param.Usage != ParameterUsage.InOut) { continue; } if (param.Type.IsPointer() && !param.Type.GetFinalPointee().IsPrimitiveType()) { param.QualifiedType = new QualifiedType(param.Type.GetFinalPointee()); } var nativeVarName = paramInfo.Name; var ctx = new MarshalContext(Context, CurrentIndentation) { ArgName = nativeVarName, ReturnVarName = nativeVarName, ReturnType = param.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); param.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) { Write(marshal.Context.Before); } WriteLine("{0} = {1};", param.Name, marshal.Context.Return); } if (isValueType && !IsNativeFunctionOrStaticMethod(function)) { GenerateStructMarshaling(@class, valueMarshalName + "."); } if (needsReturn) { var retTypeName = retType.Visit(CTypePrinter).ToString(); var isIntPtr = retTypeName.Contains("IntPtr"); if (retType.Type.IsPointer() && (isIntPtr || retTypeName.EndsWith("^", StringComparison.Ordinal))) { WriteLine("if ({0} == nullptr) return {1};", returnIdentifier, isIntPtr ? "::System::IntPtr()" : "nullptr"); } var ctx = new MarshalContext(Context, CurrentIndentation) { ArgName = returnIdentifier, ReturnVarName = returnIdentifier, ReturnType = retType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); retType.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) { Write(marshal.Context.Before); } // Special case for indexer - needs to dereference if the internal // function is a pointer type and the property is not. if (retType.Type.IsPointer() && retType.Type.GetPointee().Equals(publicRetType) && publicRetType.IsPrimitiveType()) { WriteLine("return *({0});", marshal.Context.Return); } else if (retType.Type.IsReference() && publicRetType.IsReference()) { WriteLine("return ({0})({1});", publicRetType, marshal.Context.Return); } else { WriteLine("return {0};", marshal.Context.Return); } } }
public CSharpTypePrinterResult VisitArrayType(ArrayType array, TypeQualifiers quals) { if (ContextKind == CSharpTypePrinterContextKind.Native && array.SizeType == ArrayType.ArraySize.Constant) { Type arrayType = array.Type.Desugar(); PrimitiveType primitiveType; if ((arrayType.IsPointerToPrimitiveType(out primitiveType) && !(arrayType is FunctionType)) || (arrayType.IsPrimitiveType() && MarshalKind != CSharpMarshalKind.NativeField)) { if (primitiveType == PrimitiveType.Void) { return("void*"); } return(string.Format("{0}", array.Type.Visit(this, quals))); } if (TypePrinterContext.Parameter != null) { return(string.Format("global::System.IntPtr")); } Enumeration @enum; if (arrayType.TryGetEnum(out @enum)) { return(new CSharpTypePrinterResult { Type = string.Format("fixed {0}", @enum.BuiltinType), NameSuffix = string.Format("[{0}]", array.Size) }); } Class @class; if (arrayType.TryGetClass(out @class)) { return(new CSharpTypePrinterResult { Type = "fixed byte", NameSuffix = string.Format("[{0}]", array.Size * @class.Layout.Size) }); } var arrayElemType = array.Type.Visit(this, quals).ToString(); // C# does not support fixed arrays of machine pointer type (void* or IntPtr). // In that case, replace it by a pointer to an integer type of the same size. if (arrayElemType == IntPtrType) { arrayElemType = Context.TargetInfo.PointerWidth == 64 ? "long" : "int"; } // Do not write the fixed keyword multiple times for nested array types var fixedKeyword = array.Type is ArrayType ? string.Empty : "fixed "; return(new CSharpTypePrinterResult { Type = string.Format("{0}{1}", fixedKeyword, arrayElemType), NameSuffix = string.Format("[{0}]", array.Size) }); } // const char* and const char[] are the same so we can use a string if (array.SizeType == ArrayType.ArraySize.Incomplete && array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) && array.QualifiedType.Qualifiers.IsConst) { return("string"); } return(string.Format("{0}{1}", array.Type.Visit(this), array.SizeType == ArrayType.ArraySize.Constant ? "[]" : (ContextKind == CSharpTypePrinterContextKind.Managed ? "*" : string.Empty))); // C# only supports fixed arrays in unsafe sections // and they are constrained to a set of built-in types. }