From 7a347a9060121851b544d6303edd712021612eb4 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Mon, 27 Jan 2025 12:58:31 -0500 Subject: [PATCH] [Rgen] Generate casting expressions for native enums. --- .../DataModel/TypeInfo.cs | 2 +- .../BindingSyntaxFactory.ObjCRuntime.cs | 35 +++++++++- .../Extensions/SpecialTypeExtensions.cs | 2 +- .../DataModel/TypeInfoToMarshallTypeTests.cs | 2 +- .../BindingSyntaxFactoryObjCRuntimeTests.cs | 65 +++++++++++++++++++ .../TestDataFactory.cs | 5 +- 6 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 tests/rgen/Microsoft.Macios.Generator.Tests/Emitters/BindingSyntaxFactoryObjCRuntimeTests.cs diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs index 9ec45041ef0..b4b0b82903c 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs @@ -235,7 +235,7 @@ public override int GetHashCode () const string IntPtr = "IntPtr"; const string UIntPtr = "UIntPtr"; - public string? ToMarshallType (ReferenceKind referenceKind) + public string? ToMarshallType () { #pragma warning disable format var type = this switch { diff --git a/src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.ObjCRuntime.cs b/src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.ObjCRuntime.cs index 98b7b6c402c..6e042903ea8 100644 --- a/src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.ObjCRuntime.cs +++ b/src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.ObjCRuntime.cs @@ -5,10 +5,13 @@ using System.Collections.Immutable; using System.Linq; using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.DataModel; using Microsoft.Macios.Generator.Extensions; using TypeInfo = Microsoft.Macios.Generator.DataModel.TypeInfo; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Microsoft.Macios.Generator.Emitters; @@ -16,6 +19,34 @@ static partial class BindingSyntaxFactory { readonly static string objc_msgSend = "objc_msgSend"; readonly static string objc_msgSendSuper = "objc_msgSendSuper"; + /// + /// Returns the expression needed to cast a parameter to its native type. + /// + /// The parameter whose castin we need to generate. The type info has to be + /// and enum and be marked as native. If it is not the method returns null + /// + internal static CastExpressionSyntax? CastToNative (in Parameter parameter) + { + // not an enum and not a native value. we cannot calculate the casting expression. + if (!parameter.Type.IsEnum || !parameter.Type.IsNativeEnum) + return null; + + // build a casting expression based on the marshall type of the typeinfo + var marshalType = parameter.Type.ToMarshallType (); + if (marshalType == null) + // cannot calculate the marshal, return null + return null; + + var enumBackingValue = parameter.Type.EnumUnderlyingType.Value.GetKeyword (); + var castExpression = CastExpression (IdentifierName (marshalType), // (IntPtr/UIntPtr) cast + CastExpression ( + IdentifierName (enumBackingValue), + IdentifierName (parameter.Name) + .WithLeadingTrivia (Space)) + .WithLeadingTrivia (Space)); // (backingfield) (variable) cast + return castExpression; + } + static string? GetObjCMessageSendMethodName (ExportData exportData, TypeInfo returnType, ImmutableArray parameters, bool isSuper = false, bool isStret = false) where T : Enum { @@ -42,7 +73,7 @@ static partial class BindingSyntaxFactory { } // return types do not have a reference kind - sb.Append (returnType.ToMarshallType (ReferenceKind.None)); + sb.Append (returnType.ToMarshallType ()); sb.Append ('_'); // append the msg method based if it is for super or not, do not append '_' intimidatingly, since if we do // not have parameters, we are done @@ -53,7 +84,7 @@ static partial class BindingSyntaxFactory { // loop over params and get their native handler name if (parameters.Length > 0) { sb.Append ('_'); - sb.AppendJoin ('_', parameters.Select (p => p.Type.ToMarshallType (p.ReferenceKind))); + sb.AppendJoin ('_', parameters.Select (p => p.Type.ToMarshallType ())); } // check if we do have a custom marshall exception set for the export diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/SpecialTypeExtensions.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/SpecialTypeExtensions.cs index 6e14d5ca519..21049b62196 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/SpecialTypeExtensions.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/SpecialTypeExtensions.cs @@ -17,7 +17,7 @@ static class SpecialTypeExtensions { /// /// The special type to convert. /// The string representation of the keyword. - public static string? GetKeyword (this SpecialType self) + public static string GetKeyword (this SpecialType self) { var kind = self switch { SpecialType.System_Void => SyntaxKind.VoidKeyword, diff --git a/tests/rgen/Microsoft.Macios.Generator.Tests/DataModel/TypeInfoToMarshallTypeTests.cs b/tests/rgen/Microsoft.Macios.Generator.Tests/DataModel/TypeInfoToMarshallTypeTests.cs index 4ac0910c840..6f50de75e44 100644 --- a/tests/rgen/Microsoft.Macios.Generator.Tests/DataModel/TypeInfoToMarshallTypeTests.cs +++ b/tests/rgen/Microsoft.Macios.Generator.Tests/DataModel/TypeInfoToMarshallTypeTests.cs @@ -205,7 +205,7 @@ void ToMarshallType (ApplePlatform platform, string inputText, string expectedTy Assert.NotNull (declaration); Assert.True (Property.TryCreate (declaration, semanticModel, out var changes)); Assert.NotNull (changes); - var marshall = changes.Value.ReturnType.ToMarshallType (ReferenceKind.None); + var marshall = changes.Value.ReturnType.ToMarshallType (); Assert.NotNull (marshall); Assert.Equal (expectedTypeName, marshall); } diff --git a/tests/rgen/Microsoft.Macios.Generator.Tests/Emitters/BindingSyntaxFactoryObjCRuntimeTests.cs b/tests/rgen/Microsoft.Macios.Generator.Tests/Emitters/BindingSyntaxFactoryObjCRuntimeTests.cs new file mode 100644 index 00000000000..db0b1c914df --- /dev/null +++ b/tests/rgen/Microsoft.Macios.Generator.Tests/Emitters/BindingSyntaxFactoryObjCRuntimeTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections; +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.Macios.Generator.DataModel; +using Xunit; +using static Microsoft.Macios.Generator.Emitters.BindingSyntaxFactory; +using static Microsoft.Macios.Generator.Tests.TestDataFactory; + +namespace Microsoft.Macios.Generator.Tests.Emitters; + +public class BindingSyntaxFactoryObjCRuntimeTests { + + class TestDataCodeChangesFromClassDeclaration : IEnumerable { + public IEnumerator GetEnumerator () + { + + // not enum parameter + var boolParam = new Parameter ( + position: 0, + type: ReturnTypeForBool (), + name: "myParam"); + yield return [boolParam, null!]; + + // not smart enum parameter + var enumParam = new Parameter ( + position: 0, + type: ReturnTypeForEnum ("MyEnum", isNativeEnum: false), + name: "myParam"); + + yield return [enumParam, null!]; + + // int64 + var byteEnum = new Parameter ( + position: 0, + type: ReturnTypeForEnum ("MyEnum", isNativeEnum: true, underlyingType: SpecialType.System_Int64), + name: "myParam"); + yield return [byteEnum, "(IntPtr) (long) myParam"]; + + // uint64 + var int64Enum = new Parameter ( + position: 0, + type: ReturnTypeForEnum ("MyEnum", isNativeEnum: true, underlyingType: SpecialType.System_UInt64), + name: "myParam"); + yield return [int64Enum, "(UIntPtr) (ulong) myParam"]; + } + + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); + } + + [Theory] + [ClassData(typeof(TestDataCodeChangesFromClassDeclaration))] + void CastToNativeTests (Parameter parameter, string? expectedCast) + { + var expression = CastToNative (parameter); + if (expectedCast is null) { + Assert.Null (expression); + } else { + Assert.NotNull (expression); + Assert.Equal (expectedCast, expression?.ToString ()); + } + } +} diff --git a/tests/rgen/Microsoft.Macios.Generator.Tests/TestDataFactory.cs b/tests/rgen/Microsoft.Macios.Generator.Tests/TestDataFactory.cs index 5c28ac2e00d..6fa52c4f788 100644 --- a/tests/rgen/Microsoft.Macios.Generator.Tests/TestDataFactory.cs +++ b/tests/rgen/Microsoft.Macios.Generator.Tests/TestDataFactory.cs @@ -181,7 +181,8 @@ public static TypeInfo ReturnTypeForStruct (string structName) isStruct: true ) { Parents = ["System.ValueType", "object"] }; - public static TypeInfo ReturnTypeForEnum (string enumName, bool isSmartEnum = false, bool isNativeEnum = false) + public static TypeInfo ReturnTypeForEnum (string enumName, bool isSmartEnum = false, bool isNativeEnum = false, + SpecialType underlyingType = SpecialType.System_Int32) => new ( name: enumName, isBlittable: true, @@ -199,7 +200,7 @@ public static TypeInfo ReturnTypeForEnum (string enumName, bool isSmartEnum = fa "System.ISpanFormattable" ], IsNativeEnum = isNativeEnum, - EnumUnderlyingType = SpecialType.System_Int32, + EnumUnderlyingType = underlyingType, }; public static TypeInfo ReturnTypeForArray (string type, bool isNullable = false, bool isBlittable = false)