-
Notifications
You must be signed in to change notification settings - Fork 520
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Rgen] Provide a factory method that creates the objc msg send calls. (…
…#22190) Create a factory method that will create the invoke expression for a objc msg method. This factory will prepend the two first parameters, handle and selector, and will add any extra argument nodes to the call. --------- Co-authored-by: GitHub Actions Autoformatter <github-actions-autoformatter@xamarin.com>
- Loading branch information
1 parent
a24d91d
commit de74ece
Showing
3 changed files
with
184 additions
and
3 deletions.
There are no files selected for viewing
97 changes: 96 additions & 1 deletion
97
src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.Runtime.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,110 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
|
||
namespace Microsoft.Macios.Generator.Emitters; | ||
|
||
static partial class BindingSyntaxFactory { | ||
readonly static string Runtime = "Runtime"; | ||
public const string Runtime = "Runtime"; | ||
public const string ClassPtr = "class_ptr"; | ||
|
||
public static CompilationUnitSyntax GetNSObject (string nsObjectType, ArgumentListSyntax argumentList, | ||
bool suppressNullableWarning = false) | ||
=> StaticInvocationGenericExpression (Runtime, "GetNSObject", nsObjectType, argumentList, | ||
suppressNullableWarning); | ||
|
||
/// <summary> | ||
/// Returns the expression to get the handle of a selector. | ||
/// </summary> | ||
/// <param name="selector">The selector whose handle we want to retrieve.</param> | ||
/// <returns>The expression to retrieve a selector handle.</returns> | ||
public static InvocationExpressionSyntax GetHandle (string selector) | ||
{ | ||
// (selector) | ||
var args = ArgumentList (SingletonSeparatedList ( | ||
Argument (LiteralExpression ( | ||
SyntaxKind.StringLiteralExpression, | ||
Literal (selector))))).NormalizeWhitespace (); | ||
|
||
// Selector.GetHandle (selector) | ||
return InvocationExpression ( | ||
MemberAccessExpression ( | ||
SyntaxKind.SimpleMemberAccessExpression, | ||
IdentifierName ("Selector"), | ||
IdentifierName ("GetHandle").WithTrailingTrivia (Space))) | ||
.WithArgumentList (args); | ||
} | ||
|
||
/// <summary> | ||
/// Generates the "this.Handle" expression. | ||
/// </summary> | ||
/// <returns></returns> | ||
public static MemberAccessExpressionSyntax ThisHandle () | ||
{ | ||
return MemberAccessExpression ( | ||
SyntaxKind.SimpleMemberAccessExpression, | ||
ThisExpression (), | ||
IdentifierName ("Handle")); | ||
} | ||
|
||
/// <summary> | ||
/// Generates the expression to call the objc_msgSend method. | ||
/// </summary> | ||
/// <param name="objcMsgSendMethod">The name of the method in the messaging namespace.</param> | ||
/// <param name="selector">The selector.</param> | ||
/// <param name="parameters">An optional argument list.</param> | ||
/// <returns>The expression needed to call a specific messaging method.</returns> | ||
public static InvocationExpressionSyntax MessagingInvocation (string objcMsgSendMethod, string selector, | ||
ImmutableArray<ArgumentSyntax> parameters = default) | ||
{ | ||
// the size of the arguments is 2 + the optional arguments | ||
// [0] = the handle | ||
// [1] = the selector | ||
// [2] = the arguments | ||
// but to be able to use the SeparatedList we need to add a comma for each argument | ||
// except for the last one, so we need to add parametersCount - 1 commas | ||
var parametersCount = 2 + parameters.Length; | ||
var args = new SyntaxNodeOrToken [(2 * parametersCount) - 1]; | ||
// the first two arguments are the selector and the handle, we add those by hand | ||
args [0] = Argument (ThisHandle ()); | ||
args [1] = Token (SyntaxKind.CommaToken).WithTrailingTrivia (Space); | ||
args [2] = Argument (GetHandle (selector)); | ||
|
||
// we need to add the commas and the arguments provided by the user of the api | ||
if (parameters.Length > 0) { | ||
// add a comma because we know we added the selector | ||
args [3] = Token (SyntaxKind.CommaToken).WithTrailingTrivia (Space); | ||
var argsIndex = 4; // start at 4 because we added the first 2 parameters + 2 separators | ||
var parametersIndex = 0; | ||
while (argsIndex < args.Length) { | ||
var currentParameter = parameters [parametersIndex++]; | ||
args [argsIndex++] = currentParameter; | ||
if (argsIndex < args.Length - 1) { | ||
args [argsIndex++] = Token (SyntaxKind.CommaToken).WithTrailingTrivia (Space); | ||
} | ||
} | ||
} | ||
|
||
// generates: (this.Handle, Selector.GetHandle (selector), args) | ||
var argumentList = ArgumentList (SeparatedList<ArgumentSyntax> (args)); | ||
// generates: ObjCRuntime.Messaging.objc_msgSend (this.Handle, Selector.GetHandle (selector), args) | ||
var invocation = InvocationExpression ( | ||
MemberAccessExpression ( | ||
SyntaxKind.SimpleMemberAccessExpression, | ||
MemberAccessExpression ( | ||
SyntaxKind.SimpleMemberAccessExpression, | ||
AliasQualifiedName ( | ||
IdentifierName ( | ||
Token (SyntaxKind.GlobalKeyword)), | ||
IdentifierName ("ObjCRuntime")), | ||
IdentifierName ("Messaging")), | ||
IdentifierName (objcMsgSendMethod).WithTrailingTrivia (Space))) | ||
.WithArgumentList (argumentList); | ||
return invocation; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
tests/rgen/Microsoft.Macios.Generator.Tests/Emitters/BindingSyntaxFactoryRuntimeTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Xunit; | ||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
using static Microsoft.Macios.Generator.Emitters.BindingSyntaxFactory; | ||
|
||
namespace Microsoft.Macios.Generator.Tests.Emitters; | ||
|
||
public class BindingSyntaxFactoryRuntimeTests { | ||
|
||
[Theory] | ||
[InlineData ("Test", "Selector.GetHandle (\"Test\")")] | ||
[InlineData ("name", "Selector.GetHandle (\"name\")")] | ||
[InlineData ("setName:", "Selector.GetHandle (\"setName:\")")] | ||
void GetHandleTest (string selector, string expectedDeclaration) | ||
{ | ||
var declaration = GetHandle (selector); | ||
Assert.Equal (expectedDeclaration, declaration.ToFullString ()); | ||
} | ||
|
||
class TestDataMessagingInvocationTests : IEnumerable<object []> { | ||
public IEnumerator<object []> GetEnumerator () | ||
{ | ||
// no extra params | ||
yield return [ | ||
"IntPtr_objc_msgSend", | ||
"string", | ||
ImmutableArray<ArgumentSyntax>.Empty, | ||
"global::ObjCRuntime.Messaging.IntPtr_objc_msgSend (this.Handle, Selector.GetHandle (\"string\"))" | ||
]; | ||
|
||
// one param extra | ||
ImmutableArray<ArgumentSyntax> args = ImmutableArray.Create ( | ||
Argument (IdentifierName ("arg1")) | ||
); | ||
yield return [ | ||
"IntPtr_objc_msgSend", | ||
"string", | ||
args, | ||
"global::ObjCRuntime.Messaging.IntPtr_objc_msgSend (this.Handle, Selector.GetHandle (\"string\"), arg1)" | ||
]; | ||
|
||
// several params | ||
args = ImmutableArray.Create ( | ||
Argument (IdentifierName ("arg1")), | ||
Argument (IdentifierName ("arg2")), | ||
Argument (IdentifierName ("arg3")) | ||
); | ||
yield return [ | ||
"IntPtr_objc_msgSend", | ||
"string", | ||
args, | ||
"global::ObjCRuntime.Messaging.IntPtr_objc_msgSend (this.Handle, Selector.GetHandle (\"string\"), arg1, arg2, arg3)" | ||
]; | ||
|
||
// out parameter | ||
args = ImmutableArray.Create ( | ||
Argument (PrefixUnaryExpression (SyntaxKind.AddressOfExpression, IdentifierName ("errorValue"))) | ||
); | ||
|
||
yield return [ | ||
"IntPtr_objc_msgSend", | ||
"string", | ||
args, | ||
"global::ObjCRuntime.Messaging.IntPtr_objc_msgSend (this.Handle, Selector.GetHandle (\"string\"), &errorValue)" | ||
]; | ||
} | ||
|
||
IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); | ||
} | ||
|
||
[Theory] | ||
[ClassData (typeof (TestDataMessagingInvocationTests))] | ||
void MessagingInvocationTests (string objcMsgSendMethod, string selector, ImmutableArray<ArgumentSyntax> parameters, | ||
string expectedDeclaration) | ||
{ | ||
var declaration = MessagingInvocation (objcMsgSendMethod, selector, parameters); | ||
Assert.Equal (expectedDeclaration, declaration.ToFullString ()); | ||
} | ||
} |
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.