Skip to content

Commit

Permalink
[Rgen] Add a property invocations struct to be used with the syntaxt …
Browse files Browse the repository at this point in the history
…factory.

This will allow to have a struct that will contain all the needed
invocation data.

We need to update some of the uses froma CompilationUnit to a StatementSyntax,
which actually makes the code better overall while letting us use a
throw statement as the invocation statement for a property.
  • Loading branch information
mandel-macaque committed Feb 17, 2025
1 parent de74ece commit 10de30e
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 134 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -800,40 +800,7 @@ internal static LocalDeclarationStatementSyntax Using (LocalDeclarationStatement
return sb.ToString ();
}

public static (string? Getter, string? Setter) GetObjCMessageSendMethods (in Property property,
bool isSuper = false, bool isStret = false)
{
if (property.IsProperty) {
// the getter and the setter depend of the accessors that have been set for the property, we do not want
// to calculate things that we won't use. The export data used will also depend if the getter/setter has a
// export attribute attached
var getter = property.GetAccessor (AccessorKind.Getter);
string? getterMsgSend = null;
if (getter is not null) {
var getterExportData = getter.Value.ExportPropertyData ?? property.ExportPropertyData;
if (getterExportData is not null) {
getterMsgSend = GetObjCMessageSendMethodName (getterExportData.Value, property.ReturnType, [],
isSuper, isStret);
}
}

var setter = property.GetAccessor (AccessorKind.Setter);
string? setterMsgSend = null;
if (setter is not null) {
var setterExportData = setter.Value.ExportPropertyData ?? property.ExportPropertyData;
if (setterExportData is not null) {
setterMsgSend = GetObjCMessageSendMethodName (setterExportData.Value, TypeInfo.Void,
[property.ValueParameter], isSuper, isStret);
}
}

return (Getter: getterMsgSend, Setter: setterMsgSend);
}

return default;
}

public static string? GetObjCMessageSendMethod (in Method method, bool isSuper = false, bool isStret = false)
internal static string? GetObjCMessageSendMethod (in Method method, bool isSuper = false, bool isStret = false)
=> GetObjCMessageSendMethodName (method.ExportMethodData, method.ReturnType, method.Parameters, isSuper,
isStret);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.Macios.Generator.DataModel;
using TypeInfo = Microsoft.Macios.Generator.DataModel.TypeInfo;

namespace Microsoft.Macios.Generator.Emitters;

static partial class BindingSyntaxFactory {

internal static (string? Getter, string? Setter) GetObjCMessageSendMethods (in Property property,
bool isSuper = false, bool isStret = false)
{
if (property.IsProperty) {
// the getter and the setter depend of the accessors that have been set for the property, we do not want
// to calculate things that we won't use. The export data used will also depend if the getter/setter has a
// export attribute attached
var getter = property.GetAccessor (AccessorKind.Getter);
string? getterMsgSend = null;
if (getter is not null) {
var getterExportData = getter.Value.ExportPropertyData ?? property.ExportPropertyData;
if (getterExportData is not null) {
getterMsgSend = GetObjCMessageSendMethodName (getterExportData.Value, property.ReturnType, [],
isSuper, isStret);
}
}

var setter = property.GetAccessor (AccessorKind.Setter);
string? setterMsgSend = null;
if (setter is not null) {
var setterExportData = setter.Value.ExportPropertyData ?? property.ExportPropertyData;
if (setterExportData is not null) {
setterMsgSend = GetObjCMessageSendMethodName (setterExportData.Value, TypeInfo.Void,
[property.ValueParameter], isSuper, isStret);
}
}

return (Getter: getterMsgSend, Setter: setterMsgSend);
}

return default;
}

internal static PropertyInvocations GetInvocations (in Property property)
{
return new () {
Getter = (ThrowNotImplementedException (), ThrowNotImplementedException ()),
Setter = (ThrowNotImplementedException (), ThrowNotImplementedException ()),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ static partial class BindingSyntaxFactory {
public const string Runtime = "Runtime";
public const string ClassPtr = "class_ptr";

public static CompilationUnitSyntax GetNSObject (string nsObjectType, ArgumentListSyntax argumentList,
public static StatementSyntax GetNSObject (string nsObjectType, ArgumentListSyntax argumentList,
bool suppressNullableWarning = false)
=> StaticInvocationGenericExpression (Runtime, "GetNSObject", nsObjectType, argumentList,
suppressNullableWarning);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static ArgumentSyntax GetLiteralExpressionArgument (SyntaxKind kind, string lite
return Argument (LiteralExpression (kind, Literal (literal)));
}

static CompilationUnitSyntax StaticInvocationExpression (string staticClassName, string methodName,
static StatementSyntax StaticInvocationExpression (string staticClassName, string methodName,
SyntaxNodeOrToken [] argumentList, bool suppressNullableWarning = false)
{
var invocation = InvocationExpression (
Expand All @@ -33,18 +33,14 @@ static CompilationUnitSyntax StaticInvocationExpression (string staticClassName,
)
).WithArgumentList (ArgumentList (SeparatedList<ArgumentSyntax> (argumentList)).NormalizeWhitespace ());

var compilationUnit = CompilationUnit ().WithMembers (
SingletonList<MemberDeclarationSyntax> (
GlobalStatement (
ExpressionStatement (
suppressNullableWarning
? PostfixUnaryExpression (SyntaxKind.SuppressNullableWarningExpression, invocation)
: invocation))));
return compilationUnit;
return ExpressionStatement (
suppressNullableWarning
? PostfixUnaryExpression (SyntaxKind.SuppressNullableWarningExpression, invocation)
: invocation);
}


static CompilationUnitSyntax StaticInvocationGenericExpression (string staticClassName, string methodName,
static StatementSyntax StaticInvocationGenericExpression (string staticClassName, string methodName,
string genericName,
ArgumentListSyntax argumentList, bool suppressNullableWarning = false)
{
Expand All @@ -60,41 +56,41 @@ static CompilationUnitSyntax StaticInvocationGenericExpression (string staticCla
)
).WithArgumentList (argumentList);

var compilationUnit = CompilationUnit ().WithMembers (
SingletonList<MemberDeclarationSyntax> (
GlobalStatement (
ExpressionStatement (
suppressNullableWarning
? PostfixUnaryExpression (SyntaxKind.SuppressNullableWarningExpression, invocation)
: invocation
))));
return compilationUnit;
return ExpressionStatement (
suppressNullableWarning
? PostfixUnaryExpression (SyntaxKind.SuppressNullableWarningExpression, invocation)
: invocation);
}

static CompilationUnitSyntax ThrowException (string type, string message)
static StatementSyntax ThrowException (string type, string? message = null)
{
var argumentList = ArgumentList (SingletonSeparatedList (
var throwExpression = ObjectCreationExpression (IdentifierName (type));

if (message is not null) {
var argumentList = ArgumentList (SingletonSeparatedList (
GetLiteralExpressionArgument (SyntaxKind.StringLiteralExpression, message)
)).WithLeadingTrivia (Space);

var throwExpression = ThrowStatement (
ObjectCreationExpression (IdentifierName (type))
.WithArgumentList (argumentList)).NormalizeWhitespace ();
throwExpression = throwExpression.WithArgumentList (argumentList).NormalizeWhitespace ();
} else {
throwExpression = throwExpression.WithArgumentList (ArgumentList ().WithLeadingTrivia (Space));
}

return CompilationUnit ().WithMembers (
SingletonList<MemberDeclarationSyntax> (
GlobalStatement (throwExpression)));
return ThrowStatement (throwExpression).NormalizeWhitespace ();
}

static CompilationUnitSyntax ThrowNotSupportedException (string message)
static StatementSyntax ThrowNotSupportedException (string message)
=> ThrowException (type: "NotSupportedException", message: message);

static StatementSyntax ThrowNotImplementedException ()
=> ThrowException (type: "NotImplementedException");

/// <summary>
/// Generates the syntax to declare the variable used by a field property.
/// </summary>
/// <param name="property">The field property whose backing variable we want to generate.</param>
/// <returns>The variable declaration syntax.</returns>
public static CompilationUnitSyntax FieldPropertyBackingVariable (in Property property)
internal static CompilationUnitSyntax FieldPropertyBackingVariable (in Property property)
{
var variableType = property.ReturnType.FullyQualifiedName;
if (property.ReturnType.SpecialType is SpecialType.System_IntPtr or SpecialType.System_UIntPtr
Expand Down
16 changes: 9 additions & 7 deletions src/rgen/Microsoft.Macios.Generator/Emitters/ClassEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ void EmitProperties (in BindingContext context, TabbedWriter<StringWriter> class
if (property.IsField)
// ignore fields
continue;
// use the factory to generate all the needed invocations for the current
var invocations = GetInvocations (property);

// we expect to always at least have a getter
var getter = property.GetAccessor (AccessorKind.Getter);
Expand All @@ -180,19 +182,19 @@ void EmitProperties (in BindingContext context, TabbedWriter<StringWriter> class
getterBlock.WriteRaw (
$@"{tempDeclaration}
if (IsDirectBinding) {{
{tempVar} = throw new NotImplementedException();
{tempVar} = {invocations.Getter.Send}
}} else {{
{tempVar} = throw new NotImplementedException();
{tempVar} = {invocations.Getter.SendSuper}
}}
return {tempVar};
");
} else {
getterBlock.WriteRaw (
@"if (IsDirectBinding) {
throw new NotImplementedException();
} else {
throw new NotImplementedException();
}
$@"if (IsDirectBinding) {{
{invocations.Getter.Send}
}} else {{
{invocations.Getter.SendSuper}
}}
");
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Microsoft.Macios.Generator.Emitters;

/// <summary>
/// Represents all the invocations of a property.
/// </summary>
readonly record struct PropertyInvocations {

/// <summary>
/// Invocations for the getter.
/// </summary>
public (StatementSyntax Send, StatementSyntax SendSuper) Getter { get; init; }

/// <summary>
/// Invocations for the setter.
/// </summary>
public (StatementSyntax Send, StatementSyntax SendSuper) Setter { get; init; }
}

0 comments on commit 10de30e

Please sign in to comment.