Skip to content

Commit 0f70086

Browse files
authored
[bgen] Fix generating delegates with nullable return types. #17109. (#21094)
Fixes #17109.
1 parent 622ffc4 commit 0f70086

File tree

4 files changed

+53
-24
lines changed

4 files changed

+53
-24
lines changed

src/bgen/Generator.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,7 @@ void GenerateTrampolinesForQueue (TrampolineInfo [] queue)
16281628
} else {
16291629
if (ti.Convert.Length > 0)
16301630
print (ti.Convert);
1631-
print ("{0} retval = del ({1});", ti.DelegateReturnType, ti.Invoke);
1631+
print ("var retval = del ({1});", ti.DelegateReturnType, ti.Invoke);
16321632
if (ti.PostConvert.Length > 0)
16331633
print (ti.PostConvert);
16341634
print (ti.ReturnFormat, "retval");
@@ -6645,7 +6645,7 @@ public void Generate (Type type)
66456645
if (isProtocolEventBacked)
66466646
print ("[Export (\"{0}\")]", FindSelector (dtype, mi));
66476647

6648-
print ("public {0}{1} {2} ({3})", shouldOverrideDelegateString, TypeManager.RenderType (mi.ReturnType), mi.Name, RenderParameterDecl (pars));
6648+
print ("public {0}{1} {2} ({3})", shouldOverrideDelegateString, TypeManager.RenderType (mi.ReturnType, mi.ReturnTypeCustomAttributes), mi.Name, RenderParameterDecl (pars));
66496649
print ("{"); indent++;
66506650

66516651
if (mi.Name == bta.KeepRefUntil)
@@ -7451,8 +7451,6 @@ string RenderSingleParameter (ParameterInfo p, bool removeRefTypes)
74517451
name += (removeRefTypes ? "" : (p.IsOut ? "out " : "ref ")) + TypeManager.RenderType (pt, p);
74527452
} else
74537453
name += TypeManager.RenderType (pt, p);
7454-
if (!pt.IsValueType && AttributeManager.HasAttribute<NullAllowedAttribute> (p))
7455-
name += "?";
74567454
return name;
74577455
}
74587456

src/bgen/TypeManager.cs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -256,61 +256,65 @@ public string FormatTypeUsedIn (string? usedInNamespace, Type? type)
256256

257257
public string? RenderType (Type t, ICustomAttributeProvider? provider = null)
258258
{
259+
var nullable = string.Empty;
260+
if (provider is not null && !t.IsValueType && AttributeManager.HasAttribute<NullAllowedAttribute> (provider))
261+
nullable = "?";
262+
259263
if (!t.IsEnum) {
260264
switch (Type.GetTypeCode (t)) {
261265
case TypeCode.Char:
262-
return "char";
266+
return "char" + nullable;
263267
case TypeCode.String:
264-
return "string";
268+
return "string" + nullable;
265269
case TypeCode.Int32:
266-
return "int";
270+
return "int" + nullable;
267271
case TypeCode.UInt32:
268-
return "uint";
272+
return "uint" + nullable;
269273
case TypeCode.Int64:
270-
return "long";
274+
return "long" + nullable;
271275
case TypeCode.UInt64:
272-
return "ulong";
276+
return "ulong" + nullable;
273277
case TypeCode.Single:
274-
return "float";
278+
return "float" + nullable;
275279
case TypeCode.Double:
276-
return "double";
280+
return "double" + nullable;
277281
case TypeCode.Decimal:
278-
return "decimal";
282+
return "decimal" + nullable;
279283
case TypeCode.SByte:
280-
return "sbyte";
284+
return "sbyte" + nullable;
281285
case TypeCode.Byte:
282-
return "byte";
286+
return "byte" + nullable;
283287
case TypeCode.Boolean:
284-
return "bool";
288+
return "bool" + nullable;
285289
}
286290
}
287291

288292
if (t == TypeCache.System_Void)
289293
return "void";
290294

291295
if (t == TypeCache.System_IntPtr) {
292-
return AttributeManager.HasNativeAttribute (provider) ? "nint" : "IntPtr";
296+
return (AttributeManager.HasNativeAttribute (provider) ? "nint" : "IntPtr") + nullable;
293297
} else if (t == TypeCache.System_UIntPtr) {
294-
return AttributeManager.HasNativeAttribute (provider) ? "nuint" : "UIntPtr";
298+
return (AttributeManager.HasNativeAttribute (provider) ? "nuint" : "UIntPtr") + nullable;
295299
}
296300

297301
if (t.Namespace is not null) {
298302
string ns = t.Namespace;
299303
if (NamespaceCache.ImplicitNamespaces.Contains (ns) || t.IsGenericType) {
300304
var targs = t.GetGenericArguments ();
301305
if (targs.Length == 0)
302-
return t.Name;
303-
return $"global::{t.Namespace}." + t.Name.RemoveArity () + "<" + string.Join (", ", targs.Select (l => FormatTypeUsedIn (null, l)).ToArray ()) + ">";
306+
return t.Name + nullable;
307+
return $"global::{t.Namespace}." + t.Name.RemoveArity () + "<" + string.Join (", ", targs.Select (l => FormatTypeUsedIn (null, l)).ToArray ()) + ">" + nullable;
304308
}
305309
if (NamespaceCache.NamespacesThatConflictWithTypes.Contains (ns))
306-
return "global::" + t.FullName;
310+
return "global::" + t.FullName + nullable;
307311
if (t.Name == t.Namespace)
308-
return "global::" + t.FullName;
312+
return "global::" + t.FullName + nullable;
309313
else
310-
return t.FullName;
314+
return t.FullName + nullable;
311315
}
312316

313-
return t.FullName;
317+
return t.FullName + nullable;
314318
}
315319

316320
// TODO: If we ever have an API with nested properties of the same name more than

tests/generator/BGenTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,5 +1657,16 @@ public void BackingFieldType (Profile profile)
16571657
Assert.AreEqual (nuintName, nsNSUIntegerGetValue.Parameters [0].ParameterType.FullName, "NSUInteger #2");
16581658
}
16591659

1660+
[Test]
1661+
[TestCase (Profile.iOS)]
1662+
public void DelegatesWithNullableReturnType (Profile profile)
1663+
{
1664+
Configuration.IgnoreIfIgnoredPlatform (profile.AsPlatform ());
1665+
var bgen = BuildFile (profile, "tests/delegate-nullable-return.cs");
1666+
bgen.AssertNoWarnings ();
1667+
1668+
var delegateCallback = bgen.ApiAssembly.MainModule.GetType ("NS", "MyCallback").Methods.First ((v) => v.Name == "EndInvoke");
1669+
Assert.That (delegateCallback.MethodReturnType.CustomAttributes.Any (v => v.AttributeType.Name == "NullableAttribute"), "Nullable return type");
1670+
}
16601671
}
16611672
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
using Foundation;
4+
using ObjCRuntime;
5+
6+
namespace NS {
7+
[return: NullAllowed]
8+
delegate NSObject MyCallback ([NullAllowed] NSObject obj);
9+
10+
[BaseType (typeof (NSObject))]
11+
interface Widget {
12+
[Export ("foo")]
13+
[NullAllowed]
14+
MyCallback Foo { get; set; }
15+
}
16+
}

0 commit comments

Comments
 (0)