public static CSharpElement ConvertClass(CSharpConverter converter, CppClass cppClass, CSharpElement context) { if (cppClass.ClassKind != CppClassKind.Class) { return(null); } if (cppClass.Functions.All(x => (x.Flags & CppFunctionFlags.Virtual) == 0)) { return(null); } // Register the struct as soon as possible var csInterfaceName = converter.GetCSharpName(cppClass, context); var csInterface = new CSharpInterface(csInterfaceName) { CppElement = cppClass, }; var container = converter.GetCSharpContainer(cppClass, context); converter.ApplyDefaultVisibility(csInterface, container); container.Members.Add(csInterface); if (cppClass.BaseTypes.Count > 0) { var csType = converter.GetCSharpType(cppClass.BaseTypes[0].Type, context); csInterface.BaseTypes.Add(csType); } csInterface.Comment = converter.GetCSharpComment(cppClass, csInterface); return(csInterface); }
public static CSharpElement ConvertParameter(CSharpConverter converter, CppParameter cppParam, int index, CSharpElement context) { var parent = ((CSharpElement)(context as CSharpMethod) ?? (context as CSharpDelegate)); var parameters = (context as CSharpMethod)?.Parameters ?? (context as CSharpDelegate)?.Parameters; if (parameters == null) { return(null); } var csParamName = string.IsNullOrEmpty(cppParam.Name) ? "arg" + index : converter.GetCSharpName(cppParam, context); var csParam = new CSharpParameter(csParamName) { CppElement = cppParam, Parent = parent }; parameters.Add(csParam); var csParamType = converter.GetCSharpType(cppParam.Type, csParam); csParam.Index = index; csParam.ParameterType = csParamType; return(csParam); }
public static CSharpElement ConvertFunction(CSharpConverter converter, CppFunction cppFunction, CSharpElement context) { // We process only public export functions if (!cppFunction.IsPublicExport() || ((cppFunction.Flags & (CppFunctionFlags.Inline | CppFunctionFlags.Method | CppFunctionFlags.Constructor | CppFunctionFlags.Destructor)) != 0 && (cppFunction.Flags & CppFunctionFlags.Virtual) == 0)) { return(null); } // Register the struct as soon as possible var csFunction = new CSharpMethod() { CppElement = cppFunction }; var container = converter.GetCSharpContainer(cppFunction, context); converter.ApplyDefaultVisibility(csFunction, container); container.Members.Add(csFunction); converter.AddUsing(container, "System.Runtime.InteropServices"); if ((cppFunction.Flags & CppFunctionFlags.Virtual) == 0) { csFunction.Modifiers |= CSharpModifiers.Static | CSharpModifiers.Extern; } else { csFunction.Visibility = CSharpVisibility.None; } csFunction.Name = converter.GetCSharpName(cppFunction, csFunction); csFunction.Comment = converter.GetCSharpComment(cppFunction, csFunction); csFunction.ReturnType = converter.GetCSharpType(cppFunction.ReturnType, csFunction); return(csFunction); }
private CSharpElement ConvertTypedef(CSharpConverter converter, CppTypedef cppTypedef, CSharpElement context) { var elementType = cppTypedef.ElementType; if (DefaultFunctionTypeConverter.IsFunctionType(elementType, out var cppFunctionType)) { return(DefaultFunctionTypeConverter.ConvertNamedFunctionType(converter, cppFunctionType, context, cppTypedef)); } var isFromSystemIncludes = converter.IsFromSystemIncludes(cppTypedef); var csElementType = converter.GetCSharpType(elementType, context, true); var noWrap = converter.Options.TypedefCodeGenKind == CppTypedefCodeGenKind.NoWrap && !converter.Options.TypedefWrapWhiteList.Contains(cppTypedef.Name); // If: // - the typedef is from system includes and the underlying type is not a pointer // - or the typedef mode is "no-wrap" and is not in the whitelist // then we bypass entirely the typedef and return immediately the element type bool is_size_t = isFromSystemIncludes && cppTypedef.Name == "size_t"; if (noWrap || (isFromSystemIncludes && elementType.TypeKind != CppTypeKind.Pointer && !is_size_t)) { return(csElementType); } // Otherwise we generate a small wrapper struct var csStructName = converter.GetCSharpName(cppTypedef, context); var csStruct = new CSharpStruct(csStructName) { CppElement = cppTypedef, }; var container = converter.GetCSharpContainer(cppTypedef, context); converter.ApplyDefaultVisibility(csStruct, container); container.Members.Add(csStruct); csStruct.Comment = converter.GetCSharpComment(cppTypedef, csStruct); // Requires System.Runtime.InteropServices csStruct.Attributes.Add(new CSharpStructLayoutAttribute(LayoutKind.Sequential) { CharSet = converter.Options.DefaultCharSet }); // Required by StructLayout converter.AddUsing(container, "System.Runtime.InteropServices"); var name = csStruct.Name; csStruct.Modifiers |= CSharpModifiers.ReadOnly; csStruct.BaseTypes.Add(new CSharpFreeType($"IEquatable<{name}>")); // Dump the type name and attached attributes for the element type var attachedAttributes = string.Empty; var csElementTypeName = is_size_t ? "IntPtr" : converter.ConvertTypeReferenceToString(csElementType, out attachedAttributes); csStruct.Members.Add(new CSharpLineElement($"public {name}({csElementTypeName} value) => this.Value = value;")); csStruct.Members.Add(new CSharpLineElement($"{attachedAttributes}public readonly {csElementTypeName} Value;")); csStruct.Members.Add(new CSharpLineElement($"public bool Equals({name} other) => Value.Equals(other.Value);")); csStruct.Members.Add(new CSharpLineElement($"public override bool Equals(object obj) => obj is {name} other && Equals(other);")); csStruct.Members.Add(new CSharpLineElement($"public override int GetHashCode() => Value.GetHashCode();")); csStruct.Members.Add(new CSharpLineElement($"public override string ToString() => Value.ToString();")); csStruct.Members.Add(new CSharpLineElement($"public static implicit operator {csElementTypeName}({name} from) => from.Value;")); csStruct.Members.Add(new CSharpLineElement($"public static implicit operator {name}({csElementTypeName} from) => new {name}(from);")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator ==({name} left, {name} right) => left.Equals(right);")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator !=({name} left, {name} right) => !left.Equals(right);")); return(csStruct); }
public static CSharpElement ConvertField(CSharpConverter converter, CppField cppField, CSharpElement context) { // Early exit if this is a global variable (we don't handle dllexport) bool isConst = cppField.Type is CppQualifiedType qualifiedType && qualifiedType.Qualifier == CppTypeQualifier.Const; var isGlobalVariable = (!(cppField.Parent is CppClass) && !isConst) || cppField.StorageQualifier == CppStorageQualifier.Static; if (isGlobalVariable) { return null; } var isParentClass = cppField.Parent is CppClass; var csContainer = converter.GetCSharpContainer(cppField, context); var isUnion = ((cppField.Parent as CppClass)?.ClassKind ?? CppClassKind.Struct) == CppClassKind.Union; var csFieldName = converter.GetCSharpName(cppField, (CSharpElement)csContainer); if (cppField.IsBitField) { CSharpBitField csBitFieldStorage = null; for (var index = csContainer.Members.Count - 1; index >= 0; index--) { var member = csContainer.Members[index]; if (member is CSharpField csPreviousField) { csBitFieldStorage = csPreviousField as CSharpBitField; break; } } if (csBitFieldStorage == null || (csBitFieldStorage.CurrentBitWidth + cppField.BitFieldWidth) > csBitFieldStorage.MaxBitWidth) { var canonicalType = (CppPrimitiveType)cppField.Type.GetCanonicalType(); csBitFieldStorage = new CSharpBitField(BitFieldName + csContainer.Members.Count) { Visibility = CSharpVisibility.Private, }; switch (canonicalType.Kind) { case CppPrimitiveKind.Bool: csBitFieldStorage.FieldType = CSharpPrimitiveType.Byte; csBitFieldStorage.MaxBitWidth = 8; break; case CppPrimitiveKind.WChar: csBitFieldStorage.FieldType = CSharpPrimitiveType.UShort; csBitFieldStorage.MaxBitWidth = 16; break; case CppPrimitiveKind.Char: csBitFieldStorage.FieldType = CSharpPrimitiveType.Byte; csBitFieldStorage.MaxBitWidth = 8; break; case CppPrimitiveKind.Short: csBitFieldStorage.FieldType = CSharpPrimitiveType.Short; csBitFieldStorage.MaxBitWidth = 16; break; case CppPrimitiveKind.Int: csBitFieldStorage.FieldType = CSharpPrimitiveType.Int; csBitFieldStorage.MaxBitWidth = 32; break; case CppPrimitiveKind.LongLong: csBitFieldStorage.FieldType = CSharpPrimitiveType.Long; csBitFieldStorage.MaxBitWidth = 64; break; case CppPrimitiveKind.UnsignedChar: csBitFieldStorage.FieldType = CSharpPrimitiveType.Byte; csBitFieldStorage.MaxBitWidth = 8; break; case CppPrimitiveKind.UnsignedShort: csBitFieldStorage.FieldType = CSharpPrimitiveType.UShort; csBitFieldStorage.MaxBitWidth = 16; break; case CppPrimitiveKind.UnsignedInt: csBitFieldStorage.FieldType = CSharpPrimitiveType.UInt; csBitFieldStorage.MaxBitWidth = 32; break; case CppPrimitiveKind.UnsignedLongLong: csBitFieldStorage.FieldType = CSharpPrimitiveType.ULong; csBitFieldStorage.MaxBitWidth = 64; break; default: csBitFieldStorage.FieldType = new CSharpFreeType("unsupported_bitfield_type_" + canonicalType); csBitFieldStorage.MaxBitWidth = 128; break; } csContainer.Members.Add(csBitFieldStorage); } int currentBitOffset = csBitFieldStorage.CurrentBitWidth; csBitFieldStorage.CurrentBitWidth += cppField.BitFieldWidth; var csProperty = new CSharpProperty(csFieldName) { CppElement = cppField, LinkedField = csBitFieldStorage, }; converter.ApplyDefaultVisibility(csProperty, csContainer); csProperty.Comment = converter.GetCSharpComment(cppField, csProperty); var bitmask = (1L << cppField.BitFieldWidth) - 1; var bitmaskStr = $"0b{Convert.ToString(bitmask, 2)}"; var notBitMaskStr = Convert.ToString(~(bitmask << currentBitOffset), 2); if (notBitMaskStr.Length > csBitFieldStorage.MaxBitWidth) { notBitMaskStr = notBitMaskStr.Substring(notBitMaskStr.Length - csBitFieldStorage.MaxBitWidth); } csProperty.ReturnType = converter.GetCSharpType(cppField.Type, csProperty); csProperty.GetBody = (writer, element) => { writer.Write($"return unchecked(("); csProperty.ReturnType.DumpReferenceTo(writer); writer.Write(")"); writer.Write($"(({csBitFieldStorage.Name} >> {currentBitOffset}) & {bitmaskStr})"); writer.Write(");"); writer.WriteLine(); }; csProperty.SetBody = (writer, element) => { writer.Write($"{csBitFieldStorage.Name} = ({csBitFieldStorage.Name} & unchecked(("); csBitFieldStorage.FieldType.DumpReferenceTo(writer); writer.Write($")0b{notBitMaskStr})) | (((("); csBitFieldStorage.FieldType.DumpReferenceTo(writer); writer.Write(")value) & (unchecked(("); csBitFieldStorage.FieldType.DumpReferenceTo(writer); writer.Write($"){bitmaskStr})) << {currentBitOffset}));"); writer.WriteLine(); }; csContainer.Members.Add(csProperty); return csProperty; } else { var parentName = cppField.Parent is CppClass cppClass ? cppClass.Name : string.Empty; var csField = new CSharpField(csFieldName) { CppElement = cppField }; converter.ApplyDefaultVisibility(csField, csContainer); if (isConst) { if (isParentClass) { csField.Modifiers |= CSharpModifiers.ReadOnly; } else { csField.Modifiers |= CSharpModifiers.Const; } } csContainer.Members.Add(csField); csField.Comment = converter.GetCSharpComment(cppField, csField); if (isUnion) { csField.Attributes.Add(new CSharpFreeAttribute("FieldOffset(0)")); converter.AddUsing(csContainer, "System.Runtime.InteropServices"); } csField.FieldType = converter.GetCSharpType(cppField.Type, csField); if (cppField.InitExpression != null) { if (cppField.InitExpression.Kind == CppExpressionKind.Unexposed) { csField.InitValue = cppField.InitValue?.Value?.ToString(); } else { csField.InitValue = converter.ConvertExpression(cppField.InitExpression, context, csField.FieldType); } } return csField; } }
public static CSharpElement ConvertClass(CSharpConverter converter, CppClass cppClass, CSharpElement context) { // This converter supports only plain struct or union if (cppClass.ClassKind == CppClassKind.Class && cppClass.Functions.Any(x => (x.Flags & CppFunctionFlags.Virtual) != 0)) { return(null); } // Register the struct as soon as possible var csStructName = converter.GetCSharpName(cppClass, context); var csStruct = new CSharpStruct(csStructName) { CppElement = cppClass, }; var container = converter.GetCSharpContainer(cppClass, context); converter.ApplyDefaultVisibility(csStruct, container); if (container is CSharpInterface) { container = container.Parent; } container.Members.Add(csStruct); csStruct.Comment = converter.GetCSharpComment(cppClass, csStruct); bool isUnion = cppClass.ClassKind == CppClassKind.Union; // Requires System.Runtime.InteropServices csStruct.Attributes.Add(isUnion ? new CSharpStructLayoutAttribute(LayoutKind.Explicit) { CharSet = converter.Options.DefaultCharSet } : new CSharpStructLayoutAttribute(LayoutKind.Sequential) { CharSet = converter.Options.DefaultCharSet } ); // Required by StructLayout converter.AddUsing(container, "System.Runtime.InteropServices"); if (cppClass.BaseTypes.Count == 1) { var csBaseType = converter.GetCSharpType(cppClass.BaseTypes[0].Type, context, false); csStruct.Members.Add(new CSharpField("@base") { FieldType = csBaseType, Visibility = CSharpVisibility.Public }); } // For opaque type we use a standard representation if (!cppClass.IsDefinition && cppClass.Fields.Count == 0) { csStruct.Modifiers |= CSharpModifiers.ReadOnly; csStruct.BaseTypes.Add(new CSharpFreeType($"IEquatable<{csStruct.Name}>")); csStruct.Members.Add(new CSharpLineElement("private readonly IntPtr _handle;")); csStruct.Members.Add(new CSharpLineElement($"public {csStruct.Name}(IntPtr handle) => _handle = handle;")); csStruct.Members.Add(new CSharpLineElement("public IntPtr Handle => _handle;")); csStruct.Members.Add(new CSharpLineElement($"public bool Equals({csStruct.Name} other) => _handle.Equals(other._handle);")); csStruct.Members.Add(new CSharpLineElement($"public override bool Equals(object obj) => obj is {csStruct.Name} other && Equals(other);")); csStruct.Members.Add(new CSharpLineElement($"public override int GetHashCode() => _handle.GetHashCode();")); csStruct.Members.Add(new CSharpLineElement($"public override string ToString() => \"0x\" + (IntPtr.Size == 8 ? _handle.ToString(\"X16\") : _handle.ToString(\"X8\"));")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator ==({csStruct.Name} left, {csStruct.Name} right) => left.Equals(right);")); csStruct.Members.Add(new CSharpLineElement($"public static bool operator !=({csStruct.Name} left, {csStruct.Name} right) => !left.Equals(right);")); } // If we have any anonymous structs/unions for a field type // try to compute a name for them before processing them foreach (var cppField in cppClass.Fields) { var fieldType = cppField.Type; if (fieldType is CppClass cppFieldTypeClass && cppFieldTypeClass.IsAnonymous && string.IsNullOrEmpty(cppFieldTypeClass.Name)) { var parentName = string.Empty; if (cppFieldTypeClass.Parent is CppClass cppParentClass) { parentName = cppParentClass.Name; } if (cppFieldTypeClass.ClassKind == CppClassKind.Union) { parentName = parentName == string.Empty ? "union" : parentName + "_union"; } cppFieldTypeClass.Name = $"{parentName}_{cppField.Name}"; } } return(csStruct); }
public static CSharpType GetCSharpType(CSharpConverter converter, CppType cppType, CSharpElement context, bool nested) { // Early exit for primitive types if (cppType is CppPrimitiveType cppPrimitiveType) { // Special case for bool return(cppPrimitiveType.Kind == CppPrimitiveKind.Bool ? GetBoolType(converter) : CSharpHelper.GetCSharpPrimitive(cppPrimitiveType)); } // Check if a particular CppType has been already converted var csType = converter.FindCSharpType(cppType); if (csType != null) { return(csType); } // Pre-decode the type by extracting any const/pointer and get the element type directly DecodeSimpleType(cppType, out var isConst, out var isPointer, out var elementType); if (isPointer) { if (isConst && elementType.Equals(CppPrimitiveType.Char)) { // const char* => string (with marshal) csType = GetStringType(converter); } else { var pointedCSharpType = converter.GetCSharpType(elementType, context, true); var isParam = context is CSharpParameter; var isReturn = context is CSharpMethod; if (!nested && (isParam || isReturn)) { switch (elementType.TypeKind) { case CppTypeKind.Array: break; case CppTypeKind.Reference: break; case CppTypeKind.Qualified: var qualifiedType = (CppQualifiedType)elementType; csType = new CSharpRefType(qualifiedType.Qualifier == CppTypeQualifier.Const ? (isParam ? CSharpRefKind.In : CSharpRefKind.RefReadOnly) : CSharpRefKind.Ref, converter.GetCSharpType(qualifiedType.ElementType, context, true)); break; case CppTypeKind.Function: csType = pointedCSharpType; break; case CppTypeKind.Typedef: csType = new CSharpRefType(CSharpRefKind.Ref, pointedCSharpType); break; case CppTypeKind.StructOrClass: // Is the struct is an opaque definition (which can is transformed into passing the struct directly as // the struct contains the pointer) if (pointedCSharpType is CSharpStruct csStruct && csStruct.IsOpaque) { csType = csStruct; } else { csType = new CSharpRefType(isConst ? (isParam ? CSharpRefKind.In : CSharpRefKind.RefReadOnly) : CSharpRefKind.Ref, pointedCSharpType); } break;