diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index c538e421..23e40097 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -969,12 +969,7 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl) var isFixedSizedBuffer = IsTypeConstantOrIncompleteArray(indirectFieldDecl, type); var generateCompatibleCode = _config.GenerateCompatibleCode; - var typeString = string.Empty; - - if (!fieldDecl.IsBitField && (!isFixedSizedBuffer || generateCompatibleCode)) - { - typeString = "ref "; - } + var typeStringBuilder = new StringBuilder(); if (IsType(indirectFieldDecl, type, out var recordType)) { @@ -985,12 +980,17 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl) var parentRecordDeclName = GetRemappedCursorName(parentRecordDecl); var escapedParentRecordDeclName = EscapeName(parentRecordDeclName); - typeString += escapedParentRecordDeclName + '.'; + _ = typeStringBuilder.Insert(0, '.').Insert(0, escapedParentRecordDeclName); recordDecl = parentRecordDecl; } } + if (!fieldDecl.IsBitField && (!isFixedSizedBuffer || generateCompatibleCode)) + { + _ = typeStringBuilder.Insert(0, "ref "); + } + var isSupportedFixedSizedBufferType = isFixedSizedBuffer && IsSupportedFixedSizedBufferType(typeName); if (isFixedSizedBuffer) @@ -998,21 +998,22 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl) if (!generateCompatibleCode) { _outputBuilder.EmitSystemSupport(); - typeString += "Span<"; + _ = typeStringBuilder.Append("Span<"); } else if (!isSupportedFixedSizedBufferType) { - typeString += contextType + '.'; + _ = typeStringBuilder.Append(contextType).Append('.'); typeName = GetArtificialFixedSizedBufferName(fieldDecl); } } - typeString += typeName; + _ = typeStringBuilder.Append(typeName); if (isFixedSizedBuffer && !generateCompatibleCode) { - typeString += '>'; + _ = typeStringBuilder.Append('>'); } + var typeString = typeStringBuilder.ToString(); _outputBuilder.WriteRegularField(typeString, escapedName); var isIndirectPointerField = IsTypePointerOrReference(indirectFieldDecl, type) && !typeName.Equals("IntPtr", StringComparison.Ordinal) && !typeName.Equals("UIntPtr", StringComparison.Ordinal); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/UnionDeclarationTest.cs index 3f64c858..f6ff2143 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/UnionDeclarationTest.cs @@ -182,6 +182,9 @@ public abstract class UnionDeclarationTest : PInvokeGeneratorTest [TestCase("bool", "byte")] public Task TypedefTest(string nativeType, string expectedManagedType) => TypedefTestImpl(nativeType, expectedManagedType); + [Test] + public Task UnionWithAnonStructWithAnonUnion() => UnionWithAnonStructWithAnonUnionImpl(); + protected abstract Task BasicTestImpl(string nativeType, string expectedManagedType); protected abstract Task BasicTestInCModeImpl(string nativeType, string expectedManagedType); @@ -237,4 +240,6 @@ public abstract class UnionDeclarationTest : PInvokeGeneratorTest protected abstract Task SkipNonDefinitionWithNativeTypeNameTestImpl(string nativeType, string expectedManagedType); protected abstract Task TypedefTestImpl(string nativeType, string expectedManagedType); + + protected abstract Task UnionWithAnonStructWithAnonUnionImpl(); } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/UnionDeclarationTest.cs index 89e97b78..b61bebb1 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/UnionDeclarationTest.cs @@ -1449,6 +1449,134 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public unsafe partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public _AsArray_e__FixedBuffer AsArray; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + public ref IntPtr First + {{ + get + {{ + fixed (_Anonymous_e__Struct* pField = &Anonymous) + {{ + return ref pField->First; + }} + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->A; + }} + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->B; + }} + }} + }} + + public unsafe partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public IntPtr First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public IntPtr Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public IntPtr Second; + }} + }} + }} + + public partial struct _AsArray_e__FixedBuffer + {{ + public IntPtr e0; + public IntPtr e1; + + public unsafe ref IntPtr this[int index] + {{ + get + {{ + fixed (IntPtr* pThis = &e0) + {{ + return ref pThis[index]; + }} + }} + }} + }} + }} +}} "; return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/UnionDeclarationTest.cs index 260b5af5..0c7f89bd 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/UnionDeclarationTest.cs @@ -1456,6 +1456,116 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public unsafe partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public fixed int AsArray[2]; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + public ref int First + {{ + get + {{ + fixed (_Anonymous_e__Struct* pField = &Anonymous) + {{ + return ref pField->First; + }} + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->A; + }} + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->B; + }} + }} + }} + + public unsafe partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public int First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + }} + }} + }} +}} "; return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultUnix/UnionDeclarationTest.cs index db6d3a6d..450dac95 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultUnix/UnionDeclarationTest.cs @@ -1433,6 +1433,124 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpDefaultUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public _AsArray_e__FixedBuffer AsArray; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + public ref nint First + {{ + get + {{ + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.First, 1)); + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.A, 1)); + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.B, 1)); + }} + }} + + public partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public nint First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public nint Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public nint Second; + }} + }} + }} + + public partial struct _AsArray_e__FixedBuffer + {{ + public nint e0; + public nint e1; + + public ref nint this[int index] + {{ + get + {{ + return ref AsSpan()[index]; + }} + }} + + public Span AsSpan() => MemoryMarshal.CreateSpan(ref e0, 2); + }} + }} +}} "; return ValidateGeneratedCSharpDefaultUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultWindows/UnionDeclarationTest.cs index 5dae51e6..fa7cbdb3 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpDefaultWindows/UnionDeclarationTest.cs @@ -1439,6 +1439,107 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpDefaultWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public unsafe partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public fixed int AsArray[2]; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + public ref int First + {{ + get + {{ + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.First, 1)); + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.A, 1)); + }} + }} + + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.B, 1)); + }} + }} + + public partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public int First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + }} + }} + }} +}} "; return ValidateGeneratedCSharpDefaultWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/UnionDeclarationTest.cs index b1a9584e..1f8fb1f1 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/UnionDeclarationTest.cs @@ -1394,6 +1394,118 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public _AsArray_e__FixedBuffer AsArray; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + [UnscopedRef] + public ref nint First + {{ + get + {{ + return ref Anonymous.First; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + return ref Anonymous.Anonymous.A; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + return ref Anonymous.Anonymous.B; + }} + }} + + public partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public nint First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public nint Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public nint Second; + }} + }} + }} + + [InlineArray(2)] + public partial struct _AsArray_e__FixedBuffer + {{ + public nint e0; + }} + }} +}} "; return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/UnionDeclarationTest.cs index d3379efa..4e6b0ffc 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/UnionDeclarationTest.cs @@ -1400,6 +1400,118 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public _AsArray_e__FixedBuffer AsArray; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + [UnscopedRef] + public ref int First + {{ + get + {{ + return ref Anonymous.First; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + return ref Anonymous.Anonymous.A; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + return ref Anonymous.Anonymous.B; + }} + }} + + public partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public int First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + }} + }} + + [InlineArray(2)] + public partial struct _AsArray_e__FixedBuffer + {{ + public int e0; + }} + }} +}} "; return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewUnix/UnionDeclarationTest.cs index b8f83b3a..72774ebc 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewUnix/UnionDeclarationTest.cs @@ -1394,6 +1394,118 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpPreviewUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public _AsArray_e__FixedBuffer AsArray; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + [UnscopedRef] + public ref nint First + {{ + get + {{ + return ref Anonymous.First; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + return ref Anonymous.Anonymous.A; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + return ref Anonymous.Anonymous.B; + }} + }} + + public partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public nint First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public nint Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public nint Second; + }} + }} + }} + + [InlineArray(2)] + public partial struct _AsArray_e__FixedBuffer + {{ + public nint e0; + }} + }} +}} "; return ValidateGeneratedCSharpPreviewUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewWindows/UnionDeclarationTest.cs index 238748cc..e102e66c 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpPreviewWindows/UnionDeclarationTest.cs @@ -1400,6 +1400,118 @@ public partial struct MyUnion public {expectedManagedType} b; }} }} +"; + + return ValidateGeneratedCSharpPreviewWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@"using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{{ + [StructLayout(LayoutKind.Explicit)] + public partial struct _MY_UNION + {{ + [FieldOffset(0)] + [NativeTypeName(""long[2]"")] + public _AsArray_e__FixedBuffer AsArray; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L4_C5"")] + public _Anonymous_e__Struct Anonymous; + + [UnscopedRef] + public ref int First + {{ + get + {{ + return ref Anonymous.First; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct A + {{ + get + {{ + return ref Anonymous.Anonymous.A; + }} + }} + + [UnscopedRef] + public ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct B + {{ + get + {{ + return ref Anonymous.Anonymous.B; + }} + }} + + public partial struct _Anonymous_e__Struct + {{ + [NativeTypeName(""long"")] + public int First; + + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C9"")] + public _Anonymous_e__Union Anonymous; + + [StructLayout(LayoutKind.Explicit)] + public partial struct _Anonymous_e__Union + {{ + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L9_C13"")] + public _A_e__Struct A; + + [FieldOffset(0)] + [NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C13"")] + public _B_e__Struct B; + + public partial struct _A_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + + public partial struct _B_e__Struct + {{ + [NativeTypeName(""long"")] + public int Second; + }} + }} + }} + + [InlineArray(2)] + public partial struct _AsArray_e__FixedBuffer + {{ + public int e0; + }} + }} +}} "; return ValidateGeneratedCSharpPreviewWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/UnionDeclarationTest.cs index d95cb143..07b48d38 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/UnionDeclarationTest.cs @@ -1338,6 +1338,120 @@ union MyUnion +"; + + return ValidateGeneratedXmlCompatibleUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + IntPtr + + + _Anonymous_e__Struct + + + ref IntPtr + + fixed (_Anonymous_e__Struct* pField = &Anonymous) + {{ + return ref pField->First; + }} + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->A; + }} + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->B; + }} + + + + + IntPtr + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + IntPtr + + + + + IntPtr + + + + + + + IntPtr + + + IntPtr + + + ref IntPtr + + int + + + fixed (IntPtr* pThis = &e0) + {{ + return ref pThis[index]; + }} + + + + + + "; return ValidateGeneratedXmlCompatibleUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/UnionDeclarationTest.cs index 97cf46ce..3e1ae4f3 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/UnionDeclarationTest.cs @@ -1344,6 +1344,100 @@ union MyUnion +"; + + return ValidateGeneratedXmlCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + int + + + _Anonymous_e__Struct + + + ref int + + fixed (_Anonymous_e__Struct* pField = &Anonymous) + {{ + return ref pField->First; + }} + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->A; + }} + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + fixed (_Anonymous_e__Struct._Anonymous_e__Union* pField = &Anonymous.Anonymous) + {{ + return ref pField->B; + }} + + + + + int + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + int + + + + + int + + + + + + + "; return ValidateGeneratedXmlCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultUnix/UnionDeclarationTest.cs index 3b39053e..14b87e28 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultUnix/UnionDeclarationTest.cs @@ -1324,6 +1324,112 @@ union MyUnion +"; + + return ValidateGeneratedXmlDefaultUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + nint + + + _Anonymous_e__Struct + + + ref nint + + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.First, 1)); + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.A, 1)); + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.B, 1)); + + + + + nint + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + nint + + + + + nint + + + + + + + nint + + + nint + + + ref nint + + int + + + return ref AsSpan()[index]; + + + + Span<nint> + MemoryMarshal.CreateSpan(ref e0, 2); + + + + + "; return ValidateGeneratedXmlDefaultUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultWindows/UnionDeclarationTest.cs index 6064c700..74231b71 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlDefaultWindows/UnionDeclarationTest.cs @@ -1330,6 +1330,91 @@ union MyUnion +"; + + return ValidateGeneratedXmlDefaultWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + int + + + _Anonymous_e__Struct + + + ref int + + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.First, 1)); + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.A, 1)); + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + return ref MemoryMarshal.GetReference(MemoryMarshal.CreateSpan(ref Anonymous.Anonymous.B, 1)); + + + + + int + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + int + + + + + int + + + + + + + "; return ValidateGeneratedXmlDefaultWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/UnionDeclarationTest.cs index 456dea7c..d989592e 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/UnionDeclarationTest.cs @@ -1213,6 +1213,97 @@ union MyUnion +"; + + return ValidateGeneratedXmlLatestUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + nint + + + _Anonymous_e__Struct + + + ref nint + + return ref Anonymous.First; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + return ref Anonymous.Anonymous.A; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + return ref Anonymous.Anonymous.B; + + + + + nint + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + nint + + + + + nint + + + + + + InlineArray(2) + + nint + + + + + "; return ValidateGeneratedXmlLatestUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/UnionDeclarationTest.cs index 85d7ac1e..1fda6ad0 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/UnionDeclarationTest.cs @@ -1219,6 +1219,97 @@ union MyUnion +"; + + return ValidateGeneratedXmlLatestWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + int + + + _Anonymous_e__Struct + + + ref int + + return ref Anonymous.First; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + return ref Anonymous.Anonymous.A; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + return ref Anonymous.Anonymous.B; + + + + + int + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + int + + + + + int + + + + + + InlineArray(2) + + int + + + + + "; return ValidateGeneratedXmlLatestWindowsBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewUnix/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewUnix/UnionDeclarationTest.cs index f2b921fb..18afdd60 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewUnix/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewUnix/UnionDeclarationTest.cs @@ -1213,6 +1213,97 @@ union MyUnion +"; + + return ValidateGeneratedXmlPreviewUnixBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + nint + + + _Anonymous_e__Struct + + + ref nint + + return ref Anonymous.First; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + return ref Anonymous.Anonymous.A; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + return ref Anonymous.Anonymous.B; + + + + + nint + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + nint + + + + + nint + + + + + + InlineArray(2) + + nint + + + + + "; return ValidateGeneratedXmlPreviewUnixBindingsAsync(inputContents, expectedOutputContents); diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewWindows/UnionDeclarationTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewWindows/UnionDeclarationTest.cs index d9cdd573..92e1245d 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewWindows/UnionDeclarationTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlPreviewWindows/UnionDeclarationTest.cs @@ -1219,6 +1219,97 @@ union MyUnion +"; + + return ValidateGeneratedXmlPreviewWindowsBindingsAsync(inputContents, expectedOutputContents); + } + + protected override Task UnionWithAnonStructWithAnonUnionImpl() + { + var inputContents = $@"typedef union _MY_UNION +{{ + long AsArray[2]; + struct + {{ + long First; + union + {{ + struct + {{ + long Second; + }} A; + + struct + {{ + long Second; + }} B; + }}; + }}; +}} MY_UNION;"; + + var expectedOutputContents = $@" + + + + + int + + + _Anonymous_e__Struct + + + ref int + + return ref Anonymous.First; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._A_e__Struct + + return ref Anonymous.Anonymous.A; + + + + ref _Anonymous_e__Struct._Anonymous_e__Union._B_e__Struct + + return ref Anonymous.Anonymous.B; + + + + + int + + + _Anonymous_e__Union + + + + _A_e__Struct + + + _B_e__Struct + + + + int + + + + + int + + + + + + InlineArray(2) + + int + + + + + "; return ValidateGeneratedXmlPreviewWindowsBindingsAsync(inputContents, expectedOutputContents);