diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index fcfa5c6f..88992629 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -2748,204 +2748,282 @@ void VisitBitfieldDecl(FieldDecl fieldDecl, BitfieldDesc[] bitfieldDescs, Record _outputBuilder.BeginField(in desc); _outputBuilder.WriteRegularField(typeName, escapedName); _outputBuilder.BeginBody(); - _outputBuilder.BeginGetter(_config.GenerateAggressiveInlining, isReadOnly: !Config.GenerateCompatibleCode); - var code = _outputBuilder.BeginCSharpCode(); - - code.WriteIndented("return "); var recordDeclName = GetCursorName(recordDecl); - var isSmallType = currentSize < 4; - var isRemappedToSelf = _config.RemappedNames.TryGetValue(typeName, out var remappedTypeName) && typeName.Equals(remappedTypeName, StringComparison.Ordinal); - var isTypeMismatch = type != builtinTypeBacking; - var isUnsignedToSigned = !isTypeBackingSigned && isTypeSigned; + // Small types become uint32/int32s after shifting + var isSmallType = fieldDecl.Type.Handle.SizeOf < 4; + var isSmallTypeBacking = currentSize < 4; - var needsCast = isSmallType || isRemappedToSelf || isTypeMismatch || isUnsignedToSigned; - var needsParenFirst = !isSmallType && isUnsignedToSigned; - var needsParenSecond = !needsParenFirst || isRemappedToSelf; + // Check if field/backing types match + var isTypeMismatch = type != builtinTypeBacking; + // Signed types are sign extended when shifted + var isUnsignedToSigned = !isTypeBackingSigned && isTypeSigned; + + // Check if type is directly shiftable/maskable + // Remapped types are not guaranteed to be shiftable or maskable + // Enums are maskable, but not shiftable + var isTypeLikelyRemapped = !isTypeMismatch && (typeName != typeNameBacking); + var isTypeAnEnum = IsType(fieldDecl); + + // Main cases: // backing int, current int (value << cns) >> cns // backing int, current uint (uint)((value >> cns) & msk) - // backing uint, current int ((int)value << cns) >> cns + // backing uint, current int (int)(value << cns) >> cns // backing uint, current uint (value >> cns) & msk // backing uint, current byte (byte)((value >> cns) & msk) - // backing uint, current sbyte (sbyte)((value << cns) >> cns) + // backing uint, current sbyte (sbyte)((sbyte)(value << cns) >> cns) - if (needsCast) + // Getter { - code.Write('('); - code.BeginMarker("typeName"); - code.Write(typeName); - code.EndMarker("typeName"); - code.Write(")("); - } + _outputBuilder.BeginGetter(_config.GenerateAggressiveInlining, + isReadOnly: !Config.GenerateCompatibleCode); + var code = _outputBuilder.BeginCSharpCode(); - if ((!needsParenFirst && (bitfieldOffset != 0)) || (!isUnsignedToSigned && isTypeSigned)) - { - code.Write('('); - } + code.WriteIndented("return "); - if (!string.IsNullOrWhiteSpace(contextName)) - { - code.BeginMarker("contextName"); - code.Write(contextName); - code.EndMarker("contextName"); - code.Write('.'); - } + var needsCastToFinal = (isSmallType || isTypeMismatch || isUnsignedToSigned) && !isTypeAnEnum; - code.BeginMarker("bitfieldName"); - code.Write(bitfieldName); - code.EndMarker("bitfieldName"); + // This is to handle the "backing uint, current sbyte" case + var needsCastToFinalAgain = isUnsignedToSigned && isSmallType; + if (needsCastToFinalAgain) + { + code.Write('('); + code.BeginMarker("typeName"); + code.Write(typeName); + code.EndMarker("typeName"); + code.Write(")("); + } - if (isTypeSigned) - { - code.Write(" << "); - code.BeginMarker("remainingBitsMinusBitWidth"); - code.Write(remainingBits - fieldDecl.BitWidthValue); - code.EndMarker("remainingBitsMinusBitWidth"); - code.Write(')'); + if (needsCastToFinal) + { + code.Write('('); + code.BeginMarker("typeName"); + code.Write(typeName); + code.EndMarker("typeName"); + code.Write(")"); + } - code.Write(" >> "); - code.BeginMarker("currentSizeMinusBitWidth"); - code.Write((currentSize * 8) - fieldDecl.BitWidthValue); - code.EndMarker("currentSizeMinusBitWidth"); - } - else - { - if (bitfieldOffset != 0) + var needsCastToFinalParen = needsCastToFinal && !isUnsignedToSigned; + if (needsCastToFinalParen) { - code.Write(" >> "); - code.BeginMarker("bitfieldOffset"); - code.Write(bitfieldOffset); - code.EndMarker("bitfieldOffset"); + code.Write('('); + } + + var needsCastBeforeOp = isTypeLikelyRemapped || isTypeAnEnum; + if (needsCastBeforeOp) + { + code.Write('('); + code.BeginMarker("typeName"); + code.Write(typeName); + code.EndMarker("typeName"); + code.Write(")("); + } + + if (isTypeSigned) + { + code.Write('('); + + if (!string.IsNullOrWhiteSpace(contextName)) + { + code.BeginMarker("contextName"); + code.Write(contextName); + code.EndMarker("contextName"); + code.Write('.'); + } + + code.BeginMarker("bitfieldName"); + code.Write(bitfieldName); + code.EndMarker("bitfieldName"); + + code.Write(" << "); + code.BeginMarker("remainingBitsMinusBitWidth"); + code.Write(remainingBits - fieldDecl.BitWidthValue); + code.EndMarker("remainingBitsMinusBitWidth"); + code.Write(')'); + + code.Write(" >> "); + code.BeginMarker("currentSizeMinusBitWidth"); + code.Write((currentSize * 8) - fieldDecl.BitWidthValue); + code.EndMarker("currentSizeMinusBitWidth"); } + else + { + var needsOffset = bitfieldOffset != 0; + if (needsOffset) + { + code.Write('('); + } - code.Write(" & 0x"); - code.BeginMarker("bitwidthHexStringBacking"); - code.Write(bitwidthHexStringBacking); - code.EndMarker("bitwidthHexStringBacking"); - } + if (!string.IsNullOrWhiteSpace(contextName)) + { + code.BeginMarker("contextName"); + code.Write(contextName); + code.EndMarker("contextName"); + code.Write('.'); + } - if (needsCast && needsParenSecond) - { - code.Write(')'); - } + code.BeginMarker("bitfieldName"); + code.Write(bitfieldName); + code.EndMarker("bitfieldName"); - code.WriteSemicolon(); - code.WriteNewline(); - _outputBuilder.EndCSharpCode(code); - _outputBuilder.EndGetter(); + if (needsOffset) + { + code.Write(" >> "); + code.BeginMarker("bitfieldOffset"); + code.Write(bitfieldOffset); + code.EndMarker("bitfieldOffset"); - _outputBuilder.BeginSetter(_config.GenerateAggressiveInlining); - code = _outputBuilder.BeginCSharpCode(); - code.WriteIndentation(); + code.Write(')'); + } - if (!string.IsNullOrWhiteSpace(contextName)) - { - code.BeginMarker("contextName"); - code.Write(contextName); - code.EndMarker("contextName"); - code.Write('.'); - } + code.Write(" & 0x"); + code.BeginMarker("bitwidthHexStringBacking"); + code.Write(bitwidthHexStringBacking); + code.EndMarker("bitwidthHexStringBacking"); + } - code.BeginMarker("bitfieldName"); - code.Write(bitfieldName); - code.EndMarker("bitfieldName"); + if (needsCastBeforeOp) + { + code.Write(')'); + } - code.Write(" = "); + if (needsCastToFinalParen) + { + code.Write(')'); + } - if (currentSize < 4) - { - code.Write('('); - code.BeginMarker("typeNameBacking"); - code.Write(typeNameBacking); - code.EndMarker("typeNameBacking"); - code.Write(")("); - } + if (needsCastToFinalAgain) + { + code.Write(')'); + } - code.Write('('); + code.WriteSemicolon(); + code.WriteNewline(); + _outputBuilder.EndCSharpCode(code); + _outputBuilder.EndGetter(); + } - if (!string.IsNullOrWhiteSpace(contextName)) + // Setter { - code.Write(contextName); - code.Write('.'); - } + _outputBuilder.BeginSetter(_config.GenerateAggressiveInlining); + var code = _outputBuilder.BeginCSharpCode(); + code.WriteIndentation(); - code.Write(bitfieldName); + if (!string.IsNullOrWhiteSpace(contextName)) + { + code.BeginMarker("contextName"); + code.Write(contextName); + code.EndMarker("contextName"); + code.Write('.'); + } - code.Write(" & ~"); + code.BeginMarker("bitfieldName"); + code.Write(bitfieldName); + code.EndMarker("bitfieldName"); - if (bitfieldOffset != 0) - { + code.Write(" = "); + + var needsCastToFinal = isSmallTypeBacking; + if (needsCastToFinal) + { + code.Write('('); + code.BeginMarker("typeNameBacking"); + code.Write(typeNameBacking); + code.EndMarker("typeNameBacking"); + code.Write(")("); + } + + // Zero out target bits code.Write('('); - } - code.Write("0x"); - code.BeginMarker("bitwidthHexStringBacking"); - code.Write(bitwidthHexStringBacking); - code.EndMarker("bitwidthHexStringBacking"); + if (!string.IsNullOrWhiteSpace(contextName)) + { + code.Write(contextName); + code.Write('.'); + } - if (bitfieldOffset != 0) - { - code.Write(" << "); - code.BeginMarker("bitfieldOffset"); - code.Write(bitfieldOffset); - code.EndMarker("bitfieldOffset"); - code.Write(')'); - } + code.Write(bitfieldName); - code.Write(") | "); + code.Write(" & ~"); - if ((builtinType != builtinTypeBacking) && !IsType(fieldDecl)) - { - code.Write('('); - code.Write(typeNameBacking); - code.Write(')'); - } + if (bitfieldOffset != 0) + { + code.Write('('); + } - code.Write('('); + code.Write("0x"); + code.BeginMarker("bitwidthHexStringBacking"); + code.Write(bitwidthHexStringBacking); + code.EndMarker("bitwidthHexStringBacking"); - if (bitfieldOffset != 0) - { - code.Write('('); - } + if (bitfieldOffset != 0) + { + code.Write(" << "); + code.BeginMarker("bitfieldOffset"); + code.Write(bitfieldOffset); + code.EndMarker("bitfieldOffset"); + code.Write(')'); + } + + // Write to target bits + code.Write(") | "); + + var needsCastBeforeLogicalOr = isTypeMismatch && !isTypeAnEnum; + if (needsCastBeforeLogicalOr) + { + code.Write('('); + code.Write(typeNameBacking); + code.Write(")"); + } - if (IsType(fieldDecl) || isRemappedToSelf) - { code.Write('('); - code.Write(typeNameBacking); - code.Write(")(value)"); - } - else - { - code.Write("value"); - } - code.Write(" & 0x"); - code.BeginMarker("bitwidthHexString"); - code.Write(bitwidthHexString); - code.EndMarker("bitwidthHexString"); + if (bitfieldOffset != 0) + { + code.Write('('); + } - if (bitfieldOffset != 0) - { - code.Write(") << "); - code.Write(bitfieldOffset); - } + var needsCastBeforeOp = isTypeLikelyRemapped || isTypeAnEnum; + if (needsCastBeforeOp) + { + code.Write('('); + code.Write(typeNameBacking); + code.Write(")(value)"); + } + else + { + code.Write("value"); + } - code.Write(')'); + code.Write(" & 0x"); + code.BeginMarker("bitwidthHexString"); + code.Write(bitwidthHexString); + code.EndMarker("bitwidthHexString"); + + if (bitfieldOffset != 0) + { + code.Write(") << "); + code.Write(bitfieldOffset); + } - if (currentSize < 4) - { code.Write(')'); + + if (needsCastToFinal) + { + code.Write(')'); + } + + code.WriteSemicolon(); + code.WriteNewline(); + _outputBuilder.EndCSharpCode(code); + _outputBuilder.EndSetter(); } - code.WriteSemicolon(); - code.WriteNewline(); - _outputBuilder.EndCSharpCode(code); - _outputBuilder.EndSetter(); _outputBuilder.EndBody(); _outputBuilder.EndField(in desc); _outputBuilder.WriteDivider(); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CTest.cs index b386482a..22d264a7 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CTest.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading.Tasks; using NUnit.Framework; @@ -450,4 +451,555 @@ public static partial class Methods return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); } + + [Test] + [Platform("unix")] + public Task BitfieldEnumPropertySmallBackingTypeTestUnix() + { + // This test is here mainly to ensure that the sbyte case gets coverage + if (RuntimeInformation.ProcessArchitecture != Architecture.X64) + { + Assert.Ignore("This test is only valid for Unix x64"); + } + + var inputContents = @" +typedef struct Bitfield { + unsigned char bits1 : 8; + char bits2 : 8; + unsigned char bits3 : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + public partial struct Bitfield + { + public byte _bitfield1; + + [NativeTypeName(""unsigned char : 8"")] + public byte bits1 + { + readonly get + { + return (byte)(_bitfield1 & 0xFFu); + } + + set + { + _bitfield1 = (byte)((_bitfield1 & ~0xFFu) | (value & 0xFFu)); + } + } + + public sbyte _bitfield2; + + [NativeTypeName(""char : 8"")] + public sbyte bits2 + { + readonly get + { + return (sbyte)((_bitfield2 << 0) >> 0); + } + + set + { + _bitfield2 = (sbyte)((_bitfield2 & ~0xFF) | (value & 0xFF)); + } + } + + public byte _bitfield3; + + [NativeTypeName(""unsigned char : 8"")] + public byte bits3 + { + readonly get + { + return (byte)(_bitfield3 & 0xFFu); + } + + set + { + _bitfield3 = (byte)((_bitfield3 & ~0xFFu) | (value & 0xFFu)); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); + } + + [Test] + [Platform("unix")] + public Task BitfieldEnumPropertyBackingTypeTestUnix() + { + // This test is here mainly to ensure that the sbyte case gets coverage + if (RuntimeInformation.ProcessArchitecture != Architecture.X64) + { + Assert.Ignore("This test is only valid for Unix x64"); + } + + var inputContents = @" +typedef struct IntBitfield { + int bits : 8; + unsigned int bits2 : 8; +} IntBitfield; + +typedef struct UIntBitfield { + unsigned int bits1 : 8; + int bits2 : 8; + unsigned char bits3 : 8; + char bits4 : 8; +} UIntBitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + public partial struct IntBitfield + { + public int _bitfield; + + [NativeTypeName(""int : 8"")] + public int bits + { + readonly get + { + return (_bitfield << 24) >> 24; + } + + set + { + _bitfield = (_bitfield & ~0xFF) | (value & 0xFF); + } + } + + [NativeTypeName(""unsigned int : 8"")] + public uint bits2 + { + readonly get + { + return (uint)((_bitfield >> 8) & 0xFF); + } + + set + { + _bitfield = (_bitfield & ~(0xFF << 8)) | (int)((value & 0xFFu) << 8); + } + } + } + + public partial struct UIntBitfield + { + public uint _bitfield; + + [NativeTypeName(""unsigned int : 8"")] + public uint bits1 + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + + [NativeTypeName(""int : 8"")] + public int bits2 + { + readonly get + { + return (int)(_bitfield << 16) >> 24; + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 8)) | (uint)((value & 0xFF) << 8); + } + } + + [NativeTypeName(""unsigned char : 8"")] + public byte bits3 + { + readonly get + { + return (byte)((_bitfield >> 16) & 0xFFu); + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 16)) | (uint)((value & 0xFFu) << 16); + } + } + + [NativeTypeName(""char : 8"")] + public sbyte bits4 + { + readonly get + { + return (sbyte)((sbyte)(_bitfield << 0) >> 24); + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 24)) | (uint)((value & 0xFF) << 24); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); + } + + [Test] + [Platform("unix")] + public Task BitfieldEnumPropertyTypeCastTestUnix() + { + var inputContents = @" +typedef enum Flags { + Member = 0x7FFFFFFF +} Flags; + +typedef struct Bitfield { + unsigned int bits : 8; + Flags flags : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + [NativeTypeName(""unsigned int"")] + public enum Flags : uint + { + Member = 0x7FFFFFFF, + } + + public partial struct Bitfield + { + public uint _bitfield; + + [NativeTypeName(""unsigned int : 8"")] + public uint bits + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + + [NativeTypeName(""Flags : 8"")] + public Flags flags + { + readonly get + { + return (Flags)((_bitfield >> 8) & 0xFFu); + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 8)) | (((uint)(value) & 0xFFu) << 8); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); + } + + [Test] + [Platform("unix")] + public Task BitfieldTypeDefTypeCastTestUnix() + { + var inputContents = @" +typedef unsigned int Number; + +typedef struct Bitfield { + Number bits : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + public partial struct Bitfield + { + public uint _bitfield; + + [NativeTypeName(""Number : 8"")] + public uint bits + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); + } + + [Test] + [Platform("win")] // This test has slight platform-specific differences + public Task BitfieldEnumPropertyTypeCastTestWindows() + { + var inputContents = @" +typedef enum Flags { + Member = 0x7FFFFFFF +} Flags; + +typedef struct Bitfield { + unsigned int bits : 8; + Flags flags : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + public enum Flags + { + Member = 0x7FFFFFFF, + } + + public partial struct Bitfield + { + public uint _bitfield; + + [NativeTypeName(""unsigned int : 8"")] + public uint bits + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + + [NativeTypeName(""Flags : 8"")] + public Flags flags + { + readonly get + { + return (Flags)((_bitfield << 16) >> 24); + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 8)) | (((uint)(value) & 0xFF) << 8); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); + } + + [Test] + [Platform("unix")] // This test has slight platform-specific differences + public Task BitfieldEnumTypeDefPropertyTypeCast() + { + var inputContents = @" +typedef enum FlagBits { + Member = 0x7FFFFFFF +} FlagBits; +typedef unsigned int Flags; + +typedef struct Bitfield { + unsigned int bits : 8; + Flags flags : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + [NativeTypeName(""unsigned int"")] + public enum FlagBits : uint + { + Member = 0x7FFFFFFF, + } + + public partial struct Bitfield + { + public uint _bitfield; + + [NativeTypeName(""unsigned int : 8"")] + public uint bits + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + + [NativeTypeName(""Flags : 8"")] + public uint flags + { + readonly get + { + return (_bitfield >> 8) & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 8)) | ((value & 0xFFu) << 8); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, commandLineArgs: DefaultCClangCommandLineArgs, language: "c", languageStandard: DefaultCStandard); + } + + [Test] + [Platform("unix")] // This test has slight platform-specific differences + public Task BitfieldEnumTypeDefPropertyTypeCastWithRemappingTest() + { + var inputContents = @" +typedef enum FlagBits { + Member = 0x7FFFFFFF +} FlagBits; +typedef unsigned int Flags; + +typedef struct Bitfield { + unsigned int bits : 8; + Flags flags : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + [NativeTypeName(""unsigned int"")] + public enum FlagBits : uint + { + Member = 0x7FFFFFFF, + } + + public partial struct Bitfield + { + public uint _bitfield; + + [NativeTypeName(""unsigned int : 8"")] + public uint bits + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + + [NativeTypeName(""Flags : 8"")] + public FlagBits flags + { + readonly get + { + return (FlagBits)((_bitfield >> 8) & 0xFFu); + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 8)) | (((uint)(value) & 0xFFu) << 8); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, + commandLineArgs: DefaultCClangCommandLineArgs, + language: "c", + languageStandard: DefaultCStandard, + remappedNames: new Dictionary() + { + { "Flags", "FlagBits" } + }); + } + + [Test] + [Platform("unix")] // This test has slight platform-specific differences + public Task BitfieldEnumTypeDefPropertyTypeCastWithSelfRemappingTest() + { + var inputContents = @" +typedef unsigned int Flags; + +typedef struct Bitfield { + unsigned int bits : 8; + Flags flags : 8; +} Bitfield; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + public partial struct Bitfield + { + public uint _bitfield; + + [NativeTypeName(""unsigned int : 8"")] + public uint bits + { + readonly get + { + return _bitfield & 0xFFu; + } + + set + { + _bitfield = (_bitfield & ~0xFFu) | (value & 0xFFu); + } + } + + [NativeTypeName(""Flags : 8"")] + public Flags flags + { + readonly get + { + return (Flags)((_bitfield >> 8) & 0xFFu); + } + + set + { + _bitfield = (_bitfield & ~(0xFFu << 8)) | (((uint)(value) & 0xFFu) << 8); + } + } + } +} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, + commandLineArgs: DefaultCClangCommandLineArgs, + language: "c", + languageStandard: DefaultCStandard, + remappedNames: new Dictionary() + { + { "Flags", "Flags" } + }); + } }