From 0abef9e8ee717ad5a0eb5f35ea4a7ecbdc2d4736 Mon Sep 17 00:00:00 2001 From: Tim Miller Date: Wed, 1 Jul 2026 10:56:15 +0900 Subject: [PATCH 1/2] Add TreatWarningsAsErrors -> True for release builds, cleanup --- Directory.Build.props | 5 +++++ external/Directory.Build.props | 6 ++++++ src/InteropGen/Generator.cs | 9 +++++++-- src/InteropGen/NativeModel.cs | 10 +++++----- 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 Directory.Build.props create mode 100644 external/Directory.Build.props diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..8fe4025 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + true + + \ No newline at end of file diff --git a/external/Directory.Build.props b/external/Directory.Build.props new file mode 100644 index 0000000..2f205b2 --- /dev/null +++ b/external/Directory.Build.props @@ -0,0 +1,6 @@ + + + diff --git a/src/InteropGen/Generator.cs b/src/InteropGen/Generator.cs index 48667ed..40d61e6 100644 --- a/src/InteropGen/Generator.cs +++ b/src/InteropGen/Generator.cs @@ -67,7 +67,7 @@ public static void Generate(NativeModel model, CodeGen gen) } - bool TryMapCommonType(NativeType type, bool allowStrings, out string res) + bool TryMapCommonType(NativeType type, bool allowStrings, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out string res) { string? Map() { @@ -308,7 +308,12 @@ void GenerateHandleReturn(NativeHandle nativeHandleType) GenerateHandleReturn(nativeHandle); else if(f.ReturnType is NativeNullableType { ElementType: NativeHandle nativeHandleType}) { - gen.Line("if(ret == null) return null;"); + // New-suffixed factories return a SafeHandle from P/Invoke (compare to null); + // other handle-returning functions return a raw IntPtr (compare to IntPtr.Zero). + if (f.Name.EndsWith("New")) + gen.Line("if(ret == null) return null;"); + else + gen.Line("if(ret == global::System.IntPtr.Zero) return null;"); GenerateHandleReturn(nativeHandleType); } else diff --git a/src/InteropGen/NativeModel.cs b/src/InteropGen/NativeModel.cs index e94f513..7b409bc 100644 --- a/src/InteropGen/NativeModel.cs +++ b/src/InteropGen/NativeModel.cs @@ -82,7 +82,7 @@ class NativeEnum(string name) : NativeType class NativeHandle : NativeType { - public string Name { get; set; } + public required string Name { get; set; } public List Methods { get; set; } = new(); public List Factories { get; set; } = new(); public override string ToString() => Name; @@ -95,7 +95,7 @@ class ExternalNativeType(string name) : NativeType class NativeFunctionPointer : NativeType { - public NativeType ReturnType { get; set; } + public required NativeType ReturnType { get; set; } public List Parameters { get; set; } = new(); } @@ -108,9 +108,9 @@ class NativeNamedFunctionPointer(string name) : NativeFunctionPointer class NativeFunction { - public string Name { get; set; } - public NativeType ReturnType { get; set; } - public List Parameters { get; set; } + public required string Name { get; set; } + public required NativeType ReturnType { get; set; } + public required List Parameters { get; set; } } class NativeModel From 323df433957c8addcb9520c5e54e280d892220e0 Mon Sep 17 00:00:00 2001 From: Tim Miller Date: Wed, 1 Jul 2026 11:09:11 +0900 Subject: [PATCH 2/2] Make clear that it needs to be generated this way --- src/InteropGen/Generator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/InteropGen/Generator.cs b/src/InteropGen/Generator.cs index 40d61e6..d098514 100644 --- a/src/InteropGen/Generator.cs +++ b/src/InteropGen/Generator.cs @@ -296,6 +296,11 @@ string MapDotnetType(NativeType type, bool allowHandles) void GenerateHandleReturn(NativeHandle nativeHandleType) { + // Ownership follows the "New" naming rule, NOT the method/factory + // classification: a New-suffixed function whose first parameter is a + // handle is modeled as an instance method (isFactory == false) but still + // returns a freshly-created, caller-owned handle. Using isFactory here + // would emit RetainFromNative for those and over-retain (leak). if (f.Name.EndsWith("New")) gen.Line($"return new {nativeHandleType.Name}(ret);"); else @@ -308,7 +313,8 @@ void GenerateHandleReturn(NativeHandle nativeHandleType) GenerateHandleReturn(nativeHandle); else if(f.ReturnType is NativeNullableType { ElementType: NativeHandle nativeHandleType}) { - // New-suffixed factories return a SafeHandle from P/Invoke (compare to null); + // Mirror GenerateHandleReturn's New-based branch: New-suffixed + // functions return a SafeHandle from P/Invoke (compare to null); // other handle-returning functions return a raw IntPtr (compare to IntPtr.Zero). if (f.Name.EndsWith("New")) gen.Line("if(ret == null) return null;");