Skip to content

Commit

Permalink
[bgen] Add support for delegates with pointer types. (#21159)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfbjarne authored Sep 2, 2024
1 parent ff707c1 commit 3b6a5c2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/bgen/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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) {
Expand Down
15 changes: 15 additions & 0 deletions tests/generator/BGenTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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}");
}
}
}
}
15 changes: 15 additions & 0 deletions tests/generator/tests/delegate-types.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}

7 comments on commit 3b6a5c2

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.