From 3b6a5c20c6f7c9d99980893433d5454958a723a5 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Mon, 2 Sep 2024 15:02:39 +0200 Subject: [PATCH] [bgen] Add support for delegates with pointer types. (#21159) --- src/bgen/Generator.cs | 14 ++++++++++++-- tests/generator/BGenTests.cs | 15 +++++++++++++++ tests/generator/tests/delegate-types.cs | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/generator/tests/delegate-types.cs diff --git a/src/bgen/Generator.cs b/src/bgen/Generator.cs index 70481dab8973..85db12aec7c2 100644 --- a/src/bgen/Generator.cs +++ b/src/bgen/Generator.cs @@ -718,6 +718,14 @@ public TrampolineInfo MakeTrampoline (Type t) } } + if (pi.ParameterType.IsPointer && pi.ParameterType.GetElementType ().IsValueType) { + // Technically we should only allow blittable types here, but the C# compiler shows an error later on if any non-blittable types + // are used, because this ends up in the signature of a UnmanagedCallersOnly method. + pars.Add (new TrampolineParameterInfo (TypeManager.FormatType (null, pi.ParameterType), safe_name)); + invoke.Append (safe_name); + continue; + } + if (pi.ParameterType.IsSubclassOf (TypeCache.System_Delegate)) { if (!delegate_types.ContainsKey (pi.ParameterType.Name)) { delegate_types [pi.ParameterType.FullName] = pi.ParameterType.GetMethod ("Invoke"); @@ -4731,11 +4739,13 @@ group fullname by ns into g print ("[MonoNativeFunctionWrapper]\n"); var accessibility = mi.DeclaringType.IsInternal (this) ? "internal" : "public"; - print ("{3} delegate {0} {1} ({2});", + var isUnsafe = mi.GetParameters ().Any ((v => v.ParameterType.IsPointer)) || mi.ReturnType.IsPointer; + print ("{3}{4} delegate {0} {1} ({2});", TypeManager.RenderType (mi.ReturnType, mi.ReturnTypeCustomAttributes), shortName, RenderParameterDecl (mi.GetParameters ()), - accessibility); + accessibility, + isUnsafe ? " unsafe" : string.Empty); } if (group.Namespace is not null) { diff --git a/tests/generator/BGenTests.cs b/tests/generator/BGenTests.cs index 155bac29735e..26e67f552aac 100644 --- a/tests/generator/BGenTests.cs +++ b/tests/generator/BGenTests.cs @@ -1719,5 +1719,20 @@ public void DelegatesWithNullableReturnType (Profile profile) var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke"); Assert.That (delegateCallback.MethodReturnType.CustomAttributes.Any (v => v.AttributeType.Name == "NullableAttribute"), "Nullable return type"); } + + [Test] + [TestCase (Profile.iOS)] + public void DelegatesWithPointerTypes (Profile profile) + { + Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ()); + var bgen = BuildFile (profile, "tests/delegate-types.cs"); + bgen.AssertNoWarnings (); + + var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke"); + Assert.IsTrue (delegateCallback.MethodReturnType.ReturnType.IsPointer, "Pointer return type"); + foreach (var p in delegateCallback.Parameters.Where (v => v.Name != "result")) { + Assert.IsTrue (p.ParameterType.IsPointer, $"Pointer parameter type: {p.Name}"); + } + } } } diff --git a/tests/generator/tests/delegate-types.cs b/tests/generator/tests/delegate-types.cs new file mode 100644 index 000000000000..650fef631b02 --- /dev/null +++ b/tests/generator/tests/delegate-types.cs @@ -0,0 +1,15 @@ +using System; + +using Foundation; +using ObjCRuntime; + +namespace NS { + unsafe delegate byte* MyCallback (sbyte* a, short* b, ushort* c, int* d, uint* e, long* f, ulong* g, float* h, double* i); + + [BaseType (typeof (NSObject))] + interface Widget { + [Export ("foo")] + [NullAllowed] + MyCallback Foo { get; set; } + } +}