From 117ffb204a8cbdd5c44615a640859cc2bb1f2b71 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Saenz Date: Fri, 24 Jan 2025 07:06:14 -0500 Subject: [PATCH] [RGen] Implement the BindAttribute parsing logic for the transformer. --- .../Attributes/BindData.cs | 94 +++++++++++++++++++ .../Attributes/BindDataTests.cs | 92 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 src/rgen/Microsoft.Macios.Transformer/Attributes/BindData.cs create mode 100644 tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/BindDataTests.cs diff --git a/src/rgen/Microsoft.Macios.Transformer/Attributes/BindData.cs b/src/rgen/Microsoft.Macios.Transformer/Attributes/BindData.cs new file mode 100644 index 00000000000..e642e3bc2c2 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Attributes/BindData.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Macios.Transformer.Attributes; + +readonly struct BindData : IEquatable { + + public string Selector { get; } + public bool Virtual { get; init; } + + public BindData (string selector, bool isVirtual = false) + { + Selector = selector; + Virtual = isVirtual; + } + + public static bool TryParse (AttributeData attributeData, + [NotNullWhen (true)] out BindData? data) + { + data = null; + var count = attributeData.ConstructorArguments.Length; + string selector; + bool @virtual = false; + // custom marshal directive values + + switch (count) { + case 1: + selector = (string) attributeData.ConstructorArguments [0].Value!; + break; + default: + // 0 should not be an option.. + return false; + } + + if (attributeData.NamedArguments.Length == 0) { + data = new (selector); + return true; + } + + foreach (var (argumentName, value) in attributeData.NamedArguments) { + switch (argumentName) { + case "Selector": + selector = (string) value.Value!; + break; + case "Virtual": + @virtual = (bool) value.Value!; + break; + default: + data = null; + return false; + } + } + + data = new(selector) { Virtual = @virtual, }; + return true; + } + + public bool Equals (BindData other) + { + if (Selector != other.Selector) + return false; + return Virtual == other.Virtual; + } + + /// + public override bool Equals (object? obj) + { + return obj is BindData other && Equals (other); + } + + /// + public override int GetHashCode () + => HashCode.Combine (Selector, Virtual); + + + public static bool operator == (BindData x, BindData y) + { + return x.Equals (y); + } + + public static bool operator != (BindData x, BindData y) + { + return !(x == y); + } + + /// + public override string ToString () + { + return $"{{ BindSelector: '{Selector}', Virtual: {Virtual} }}"; + } +} diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/BindDataTests.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/BindDataTests.cs new file mode 100644 index 00000000000..1deb642c204 --- /dev/null +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/BindDataTests.cs @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Extensions; +using Microsoft.Macios.Transformer.Attributes; +using Xamarin.Tests; +using Xamarin.Utils; + +namespace Microsoft.Macios.Transformer.Tests.Attributes; + +public class BindDataTests : BaseTransformerTestClass { + + class TestDataTryCreate : IEnumerable { + public IEnumerator GetEnumerator () + { + var path = "/some/random/path.cs"; + var simpleBind = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV] +[MacCatalyst (13, 1)] +[DisableDefaultCtor] +[Abstract] +[BaseType (typeof (NSObject))] +interface UIFeedbackGenerator : UIInteraction { + + [Bind (""someSelector"")] + void Prepare (); +} +"; + + yield return [(Sorunce: simpleBind, Path: path), new BindData ("someSelector")]; + + var virtualBind = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV] +[MacCatalyst (13, 1)] +[DisableDefaultCtor] +[Abstract] +[BaseType (typeof (NSObject))] +interface UIFeedbackGenerator : UIInteraction { + + [Bind (""someSelector"", Virtual = true)] + void Prepare (); +} +"; + + yield return [(Sorunce: virtualBind, Path: path), new BindData ("someSelector", true)]; + } + + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); + } + + [Theory] + [AllSupportedPlatformsClassData] + void TryeCreateTests (ApplePlatform platform, (string Source, string Path) source, + BindData expectedData) + { + // create a compilation used to create the transformer + var compilation = CreateCompilation (platform, sources: source); + var syntaxTree = compilation.SyntaxTrees.ForSource (source); + Assert.NotNull (syntaxTree); + + var semanticModel = compilation.GetSemanticModel (syntaxTree); + Assert.NotNull (semanticModel); + + var declaration = syntaxTree.GetRoot () + .DescendantNodes ().OfType () + .LastOrDefault (); + Assert.NotNull (declaration); + + var symbol = semanticModel.GetDeclaredSymbol (declaration); + Assert.NotNull (symbol); + var exportData = symbol.GetAttribute ( + AttributesNames.BindAttribute, BindData.TryParse); + Assert.Equal (expectedData, exportData); + } +}