From afdd02576c9c0df6c39354c6f8117f6a1d222a6c Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Thu, 30 Jan 2025 05:59:17 -0500 Subject: [PATCH 1/2] [RGen] Add extension method to know if a symbol is wrapped. --- .../DataModel/TypeInfo.Generator.cs | 18 +- .../Extensions/TypeSymbolExtensions.Core.cs | 11 +- .../TypeSymbolExtensions.Generator.cs | 30 ++++ .../Extensions/TypeSymbolExtensionsTests.cs | 157 ++++++++++++++++++ 4 files changed, 210 insertions(+), 6 deletions(-) diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs index 4372d8ef905d..a2443a8c0408 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs @@ -7,6 +7,16 @@ namespace Microsoft.Macios.Generator.DataModel; readonly partial struct TypeInfo { + + /// + /// Return if the type represents a wrapped object from the objc world. + /// + public bool IsWrapped { get; init; } + + /// + /// Returns, if the type is an array, if its elements are a wrapped object from the objc world. + /// + public bool ArrayElementTypeIsWrapped { get; init; } internal TypeInfo (ITypeSymbol symbol) : this ( @@ -18,7 +28,6 @@ symbol is IArrayTypeSymbol arrayTypeSymbol IsNullable = symbol.NullableAnnotation == NullableAnnotation.Annotated; IsBlittable = symbol.IsBlittable (); IsSmartEnum = symbol.IsSmartEnum (); - IsArray = symbol is IArrayTypeSymbol; IsReferenceType = symbol.IsReferenceType; IsStruct = symbol.TypeKind == TypeKind.Struct; IsInterface = symbol.TypeKind == TypeKind.Interface; @@ -33,6 +42,13 @@ symbol is IArrayTypeSymbol arrayTypeSymbol parents: out parents, interfaces: out interfaces); + IsWrapped = symbol.IsWrapped (isNSObject); + if (symbol is IArrayTypeSymbol arraySymbol) { + IsArray = true; + ArrayElementTypeIsWrapped = arraySymbol.ElementType.IsWrapped (); + } + IsArray = symbol is IArrayTypeSymbol; + // try to get the named type symbol to have more educated decisions var namedTypeSymbol = symbol as INamedTypeSymbol; diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs index fb776aac311b..5433d3dead69 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs @@ -13,6 +13,11 @@ namespace Microsoft.Macios.Generator.Extensions; static partial class TypeSymbolExtensions { + + const string nativeObjectInterface = "ObjCRuntime.INativeObject"; + const string nsObjectClass = "Foundation.NSObject"; + const string dictionaryContainerClass = "Foundation.DictionaryContainer"; + /// /// Retrieve a dictionary with the attribute data of all the attributes attached to a symbol. Because /// an attribute can appear more than once, the valus are a collection of attribute data. @@ -417,11 +422,7 @@ public static void GetInheritance ( out ImmutableArray parents, out ImmutableArray interfaces) { - const string nativeObjectInterface = "ObjCRuntime.INativeObject"; - const string nsObjectClass = "Foundation.NSObject"; - const string dictionaryContainerClass = "Foundation.DictionaryContainer"; - - isNSObject = false; + isNSObject = symbol.ToDisplayString ().Trim() == nsObjectClass; isNativeObject = false; isDictionaryContainer = false; diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs index 59113974dbc2..5ce65d7d4657 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.Availability; @@ -213,4 +215,32 @@ public static bool NeedsStret (this ITypeSymbol returnType, Compilation compilat return ArmNeedStret (returnType, compilation); } + + /// + /// A type is considered wrapped if it is an Interface or is an child of the NSObject class or the NSObject + /// itself. + /// + /// The symbol to check if it is wrapped. + /// If the symbol is a NSObject of inherits from an NSObject. + /// True if the ymbol is considered to be wrapped. + public static bool IsWrapped (this ITypeSymbol symbol, bool isNSObject) + => symbol.TypeKind == TypeKind.Interface || isNSObject; + + /// + /// A type is considered wrapped if it is an Interface or is an child of the NSObject class or the NSObject + /// itself. + /// + /// The symbol to check if it is wrapped. + /// True if the ymbol is considered to be wrapped. + public static bool IsWrapped (this ITypeSymbol symbol) + { + symbol.GetInheritance ( + isNSObject: out bool isNSObject, + isNativeObject: out bool _, + isDictionaryContainer: out bool _, + parents: out ImmutableArray _, + interfaces: out ImmutableArray _); + // either we are a NSObject or we are a subclass of it + return IsWrapped (symbol, isNSObject); + } } diff --git a/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs b/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs index c6fd75559c3a..6395470abb54 100644 --- a/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs +++ b/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs @@ -1702,5 +1702,162 @@ void IsBlittable (ApplePlatform platform, string inputText, bool expectedResult) Assert.NotNull (symbol); Assert.Equal (expectedResult, symbol.Type.IsBlittable ()); } + + class TestDataIsWrapped : IEnumerable { + public IEnumerator GetEnumerator () + { + const string stringProperty = @" +using System; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public string Property { get; set; } +} +"; + yield return [stringProperty, false]; + + const string nsUuidProperty = @" +using System; +using Foundation; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public NSUuid Property { get; set; } +} +"; + yield return [nsUuidProperty, true]; + + const string nmatrix4Property = @" +using System; +using CoreGraphics; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public NMatrix4 Property { get; set; } +} +"; + + yield return [nmatrix4Property, false]; + + const string nativeHandleProperty = @" +using System; +using ObjCRuntime; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public NativeHandle Property { get; set; } +} +"; + yield return [nativeHandleProperty, false]; + + const string nsZoneProperty = @" +using System; +using Foundation; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public NSZone Property { get; set; } +} +"; + yield return [nsZoneProperty, false]; + + const string nsobjectProperty = @" +using System; +using Foundation; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public NSObject Property { get; set; } +} +"; + yield return [nsobjectProperty, true]; + + const string nssetProperty = @" +using System; +using Foundation; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public NSSet Property { get; set; } +} +"; + yield return [nssetProperty, true]; + + + const string mtlDeviceProperty = @" +using System; +using Metal; +using ObjCBindings; + +namespace NS; + +[BindingType] +public partial class MyClass { + public IMTLDevice Property { get; set; } +} +"; + yield return [mtlDeviceProperty, true]; + + const string EnumProperty = @" +using System; +using System.Runtime.InteropServices; +using ObjCBindings; + +namespace NS; + +public enum MyEnum : ulong { + First, + Second, +} + +[BindingType] +public partial class MyClass { + public MyEnum Property { get; set; } +} +"; + yield return [EnumProperty, false]; + } + + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); + } + + [Theory] + [AllSupportedPlatformsClassData] + void IsWrapped (ApplePlatform platform, string inputText, bool expectedResult) + { + var (compilation, syntaxTrees) = CreateCompilation (platform, sources: inputText); + Assert.Single (syntaxTrees); + var declaration = syntaxTrees [0].GetRoot () + .DescendantNodes () + .OfType () + .FirstOrDefault (); + Assert.NotNull (declaration); + var semanticModel = compilation.GetSemanticModel (syntaxTrees [0]); + Assert.NotNull (semanticModel); + var symbol = semanticModel.GetDeclaredSymbol (declaration); + Assert.NotNull (symbol); + Assert.Equal (expectedResult, symbol.Type.IsWrapped ()); + } } From d29d3a552d3a7174f62507426fdf3b4a84541fea Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Thu, 30 Jan 2025 11:57:04 +0000 Subject: [PATCH 2/2] Auto-format source code --- .../DataModel/TypeInfo.Generator.cs | 4 ++-- .../Extensions/TypeSymbolExtensions.Core.cs | 6 +++--- .../Extensions/TypeSymbolExtensionsTests.cs | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs index a2443a8c0408..80e8455205c0 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs @@ -7,12 +7,12 @@ namespace Microsoft.Macios.Generator.DataModel; readonly partial struct TypeInfo { - + /// /// Return if the type represents a wrapped object from the objc world. /// public bool IsWrapped { get; init; } - + /// /// Returns, if the type is an array, if its elements are a wrapped object from the objc world. /// diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs index 5433d3dead69..dbd97c096183 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs @@ -13,11 +13,11 @@ namespace Microsoft.Macios.Generator.Extensions; static partial class TypeSymbolExtensions { - + const string nativeObjectInterface = "ObjCRuntime.INativeObject"; const string nsObjectClass = "Foundation.NSObject"; const string dictionaryContainerClass = "Foundation.DictionaryContainer"; - + /// /// Retrieve a dictionary with the attribute data of all the attributes attached to a symbol. Because /// an attribute can appear more than once, the valus are a collection of attribute data. @@ -422,7 +422,7 @@ public static void GetInheritance ( out ImmutableArray parents, out ImmutableArray interfaces) { - isNSObject = symbol.ToDisplayString ().Trim() == nsObjectClass; + isNSObject = symbol.ToDisplayString ().Trim () == nsObjectClass; isNativeObject = false; isDictionaryContainer = false; diff --git a/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs b/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs index 6395470abb54..0b7181058c48 100644 --- a/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs +++ b/tests/rgen/Microsoft.Macios.Generator.Tests/Extensions/TypeSymbolExtensionsTests.cs @@ -1702,7 +1702,7 @@ void IsBlittable (ApplePlatform platform, string inputText, bool expectedResult) Assert.NotNull (symbol); Assert.Equal (expectedResult, symbol.Type.IsBlittable ()); } - + class TestDataIsWrapped : IEnumerable { public IEnumerator GetEnumerator () { @@ -1745,7 +1745,7 @@ public partial class MyClass { public NMatrix4 Property { get; set; } } "; - + yield return [nmatrix4Property, false]; const string nativeHandleProperty = @" @@ -1775,7 +1775,7 @@ public partial class MyClass { } "; yield return [nsZoneProperty, false]; - + const string nsobjectProperty = @" using System; using Foundation; @@ -1789,7 +1789,7 @@ public partial class MyClass { } "; yield return [nsobjectProperty, true]; - + const string nssetProperty = @" using System; using Foundation; @@ -1804,7 +1804,7 @@ public partial class MyClass { "; yield return [nssetProperty, true]; - + const string mtlDeviceProperty = @" using System; using Metal; @@ -1818,7 +1818,7 @@ public partial class MyClass { } "; yield return [mtlDeviceProperty, true]; - + const string EnumProperty = @" using System; using System.Runtime.InteropServices;