From 37c3d116b710ef47278bc101a99cf3d1949c23fe Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 12 Jul 2026 21:41:06 -0700 Subject: [PATCH] Fix missing semicolon on non-const global struct initializers The EndValue path for ValueKind.Unmanaged only emitted the terminating semicolon when the value was constant, so a non-const global initialized with a struct initializer list (e.g. Point p = { .x = 10, .y = 20 };) was emitted as a closing '}' with no ';', corrupting the rest of the file. Emit the semicolon for the non-const case as well, matching the constant path and the primitive/string/guid value kinds. Fixes #503 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../CSharp/CSharpOutputBuilder.VisitDecl.cs | 4 ++ .../GlobalStructInitializerTest.cs | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/ClangSharp.PInvokeGenerator.UnitTests/GlobalStructInitializerTest.cs diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs index 5060f29d..56daf313 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs @@ -224,6 +224,10 @@ public void EndValue(in ValueDesc desc) WriteLine(';'); } } + else + { + WriteLine(';'); + } break; } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/GlobalStructInitializerTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/GlobalStructInitializerTest.cs new file mode 100644 index 00000000..4415f669 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/GlobalStructInitializerTest.cs @@ -0,0 +1,43 @@ +// 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.Threading.Tasks; +using NUnit.Framework; + +namespace ClangSharp.UnitTests; + +public sealed class GlobalStructInitializerTest : PInvokeGeneratorTest +{ + // Regression test for https://github.com/dotnet/clangsharp/issues/503 + // A non-const global variable initialized with a struct initializer list was + // missing its terminating semicolon, which corrupted the rest of the file. + [Test] + public Task NonConstGlobalTest() + { + var inputContents = @"typedef struct Point { int x; int y; } Point; + +Point MyGlobalPoint = { .x = 10, .y = 20 }; +"; + + var expectedOutputContents = @"namespace ClangSharp.Test +{ + public partial struct Point + { + public int x; + + public int y; + } + + public static partial class Methods + { + public static Point MyGlobalPoint = new Point + { + x = 10, + y = 20, + }; + } +} +"; + + return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents); + } +}