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 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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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;
            }
        }
Пример #5
0
        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);
        }