Skip to content

Commit e31e352

Browse files
[Rgen] Add a factory method that will create the aux variable for handles.
When we interact with nstobjects we need to send the Hanldes as a parameter and not the managed object. This new method will generated the aux variable needed to store the handle and use it in the message send objc method.
1 parent e597395 commit e31e352

File tree

3 files changed

+139
-3
lines changed

3 files changed

+139
-3
lines changed

src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.ObjCRuntime.cs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
using Microsoft.Macios.Generator.Attributes;
1212
using Microsoft.Macios.Generator.DataModel;
1313
using Microsoft.Macios.Generator.Extensions;
14-
using TypeInfo = Microsoft.Macios.Generator.DataModel.TypeInfo;
1514
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
15+
using TypeInfo = Microsoft.Macios.Generator.DataModel.TypeInfo;
1616
using Parameter = Microsoft.Macios.Generator.DataModel.Parameter;
1717

1818
namespace Microsoft.Macios.Generator.Emitters;
@@ -167,6 +167,67 @@ static partial class BindingSyntaxFactory {
167167
: statement;
168168
}
169169

170+
/// <summary>
171+
/// Returns the aux variable for a handle object. This method will do the following:
172+
/// 1. Check if the object is nullable or not.
173+
/// 2. Use the correct GetHandle method depending on the content of the object.
174+
/// </summary>
175+
internal static LocalDeclarationStatementSyntax? GetHandleAuxVariable (in Parameter parameter,
176+
bool withNullAllowed = false)
177+
{
178+
if (!parameter.Type.IsNSObject && !parameter.Type.IsINativeObject)
179+
return null;
180+
181+
var variableName = parameter.GetNameForVariableType (Parameter.VariableType.Handle);
182+
if (variableName is null)
183+
return null;
184+
// decide about the factory based on the need of a null check
185+
InvocationExpressionSyntax factoryInvocation;
186+
if (withNullAllowed) {
187+
// generates: zone!.GetNonNullHandle (nameof (zone));
188+
factoryInvocation = InvocationExpression (
189+
MemberAccessExpression (SyntaxKind.SimpleMemberAccessExpression,
190+
PostfixUnaryExpression (
191+
SyntaxKind.SuppressNullableWarningExpression,
192+
IdentifierName (parameter.Name)),
193+
IdentifierName ("GetNonNullHandle").WithTrailingTrivia (Space)))
194+
.WithArgumentList (ArgumentList (
195+
SingletonSeparatedList<ArgumentSyntax> (Argument (
196+
InvocationExpression (
197+
IdentifierName (Identifier (TriviaList (Space), SyntaxKind.NameOfKeyword, "nameof",
198+
"nameof",
199+
TriviaList (Space))))
200+
.WithArgumentList (ArgumentList (
201+
SingletonSeparatedList<ArgumentSyntax> (
202+
Argument (IdentifierName (parameter.Name)))))))));
203+
} else {
204+
// generates: zone.GetHandle ();
205+
factoryInvocation = InvocationExpression (
206+
MemberAccessExpression (SyntaxKind.SimpleMemberAccessExpression,
207+
IdentifierName (parameter.Name),
208+
IdentifierName ("GetHandle").WithTrailingTrivia (Space)));
209+
}
210+
211+
// generates: variable = {FactoryCall}
212+
var declarator = VariableDeclarator (Identifier (variableName))
213+
.WithInitializer (EqualsValueClause (factoryInvocation.WithLeadingTrivia (Space)).WithLeadingTrivia (Space));
214+
// generates the final statement:
215+
// var x = zone.GetHandle ();
216+
// or
217+
// var x = zone!.GetNonNullHandle (nameof (constantValues));
218+
return LocalDeclarationStatement (
219+
VariableDeclaration (
220+
IdentifierName (
221+
Identifier (
222+
TriviaList (),
223+
SyntaxKind.VarKeyword,
224+
"var",
225+
"var",
226+
TriviaList ()))).WithVariables (
227+
SingletonSeparatedList (declarator.WithLeadingTrivia (Space))
228+
));
229+
}
230+
170231
static string? GetObjCMessageSendMethodName<T> (ExportData<T> exportData,
171232
TypeInfo returnType, ImmutableArray<Parameter> parameters, bool isSuper = false, bool isStret = false)
172233
where T : Enum

tests/rgen/Microsoft.Macios.Generator.Tests/Emitters/BindingSyntaxFactoryObjCRuntimeTests.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@ public IEnumerator<object []> GetEnumerator ()
177177
new Parameter (0, ReturnTypeForArray ("NSString", isNullable: true), "myParam"),
178178
"using var nsa_myParam = myParam is null ? null : NSArray.FromNSObjects (myParam);",
179179
true];
180-
181-
182180
}
183181

184182
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
@@ -196,4 +194,57 @@ void GetNSArrayAuxVariableTests (in Parameter parameter, string? expectedDeclara
196194
Assert.Equal (expectedDeclaration, declaration.ToString ());
197195
}
198196
}
197+
198+
class TestDataCodeChangesFromClassDeclaration : IEnumerable<object []> {
199+
public IEnumerator<object []> GetEnumerator ()
200+
{
201+
// nsobject type
202+
yield return [
203+
new Parameter (0, ReturnTypeForNSObject ("MyNSObject"), "myParam"),
204+
"var myParam__handle__ = myParam.GetHandle ();",
205+
false
206+
];
207+
208+
yield return [
209+
new Parameter (0, ReturnTypeForNSObject ("MyNSObject"), "myParam"),
210+
"var myParam__handle__ = myParam!.GetNonNullHandle ( nameof (myParam));",
211+
true
212+
];
213+
214+
// interface type
215+
yield return [
216+
new Parameter (0, ReturnTypeForINativeObject ("MyNativeObject"), "myParam"),
217+
"var myParam__handle__ = myParam.GetHandle ();",
218+
false
219+
];
220+
221+
yield return [
222+
new Parameter (0, ReturnTypeForINativeObject ("MyNativeObject"), "myParam"),
223+
"var myParam__handle__ = myParam!.GetNonNullHandle ( nameof (myParam));",
224+
true
225+
];
226+
227+
// value type
228+
yield return [
229+
new Parameter (0, ReturnTypeForBool (), "myParam"),
230+
null!,
231+
false
232+
];
233+
}
234+
235+
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();
236+
}
237+
238+
[Theory]
239+
[ClassData (typeof (TestDataCodeChangesFromClassDeclaration))]
240+
void GetHandleAuxVariableTests (in Parameter parameter, string? expectedDeclaration, bool withNullAllowed)
241+
{
242+
var declaration = GetHandleAuxVariable (parameter, withNullAllowed: withNullAllowed);
243+
if (expectedDeclaration is null) {
244+
Assert.Null (declaration);
245+
} else {
246+
Assert.NotNull (declaration);
247+
Assert.Equal (expectedDeclaration, declaration.ToString ());
248+
}
249+
}
199250
}

tests/rgen/Microsoft.Macios.Generator.Tests/TestDataFactory.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,28 @@ public static TypeInfo ReturnTypeForDelegate (string delegateName)
299299
"System.Runtime.Serialization.ISerializable",
300300
]
301301
};
302+
303+
public static TypeInfo ReturnTypeForNSObject (string nsObjectName, bool isNullable = false)
304+
=> new (
305+
name: nsObjectName,
306+
isNullable: isNullable,
307+
isArray: false
308+
) {
309+
IsNSObject = true,
310+
IsINativeObject = true,
311+
Parents = ["Foundation.NSObject", "object"],
312+
Interfaces = ["ObjCRuntime.INativeObject"]
313+
};
314+
315+
public static TypeInfo ReturnTypeForINativeObject (string nativeObjectName, bool isNullable = false)
316+
=> new (
317+
name: nativeObjectName,
318+
isNullable: isNullable,
319+
isArray: false
320+
) {
321+
IsNSObject = true,
322+
IsINativeObject = true,
323+
Parents = ["object"],
324+
Interfaces = ["ObjCRuntime.INativeObject"]
325+
};
302326
}

0 commit comments

Comments
 (0)