diff --git a/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs b/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs index e79a20b0515..a459f5d2cb8 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs @@ -7,7 +7,7 @@ namespace Microsoft.Macios.Transformer.Attributes; -public struct ExportData : IEquatable { +struct ExportData : IEquatable { /// /// The exported native selector. @@ -31,7 +31,7 @@ public ExportData (string? selector, ArgumentSemantic argumentSemantic) } /// - /// Try to parse the attribute data to retrieve the information of an ExportAttribute<T>. + /// Try to parse the attribute data to retrieve the information of an ExportAttribute. /// /// The attribute data to be parsed. /// The parsed data. Null if we could not parse the attribute data. diff --git a/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs b/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs index 3f7c0e824d8..cd28d44febb 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs @@ -1,25 +1,82 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; + namespace Microsoft.Macios.Transformer.Attributes; -public struct FieldData : IEquatable { +struct FieldData : IEquatable { + + public string SymbolName { get; } + public string? LibraryName { get; } + + internal FieldData (string symbolName, string? libraryName) + { + SymbolName = symbolName; + LibraryName = libraryName; + } + + internal FieldData (string symbolName) : this (symbolName, null) { } + + public static bool TryParse (AttributeData attributeData, + [NotNullWhen (true)] out FieldData? data) + { + data = default; + + var count = attributeData.ConstructorArguments.Length; + string? symbolName; + string? libraryName = null; + switch (count) { + case 1: + symbolName = (string?) attributeData.ConstructorArguments [0].Value!; + break; + case 2: + symbolName = (string?) attributeData.ConstructorArguments [0].Value!; + libraryName = (string?) attributeData.ConstructorArguments [1].Value!; + break; + default: + // 0 should not be an option. + return false; + } + + if (attributeData.NamedArguments.Length == 0) { + data = new (symbolName, libraryName); + return true; + } + + // LibraryName can be a param value + foreach (var (name, value) in attributeData.NamedArguments) { + switch (name) { + case "LibraryName": + libraryName = (string?) value.Value!; + break; + default: + data = null; + return false; + } + } + data = new (symbolName, libraryName); + return true; + } public bool Equals (FieldData other) { - throw new NotImplementedException (); + if (SymbolName != other.SymbolName) + return false; + return LibraryName == other.LibraryName; } /// public override bool Equals (object? obj) { - return obj is ExportData other && Equals (other); + return obj is FieldData other && Equals (other); } /// public override int GetHashCode () { - throw new NotImplementedException (); + return HashCode.Combine (SymbolName, LibraryName); } public static bool operator == (FieldData x, FieldData y) @@ -31,4 +88,9 @@ public override int GetHashCode () { return !(x == y); } + + public override string ToString () + { + return $"{{ SymbolName: '{SymbolName}' LibraryName: '{LibraryName ?? "null"}' }}"; + } } diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/DataModel/ExportDataTests.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/ExportDataTests.cs similarity index 93% rename from tests/rgen/Microsoft.Macios.Transformer.Tests/DataModel/ExportDataTests.cs rename to tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/ExportDataTests.cs index d810b2496d3..ad826e332df 100644 --- a/tests/rgen/Microsoft.Macios.Transformer.Tests/DataModel/ExportDataTests.cs +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/ExportDataTests.cs @@ -4,13 +4,13 @@ using System.Collections; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Extensions; using Microsoft.Macios.Transformer.Attributes; +using ObjCRuntime; using Xamarin.Tests; using Xamarin.Utils; -using Microsoft.Macios.Generator.Extensions; -using ObjCRuntime; -namespace Microsoft.Macios.Transformer.Tests.DataModel; +namespace Microsoft.Macios.Transformer.Tests.Attributes; public class ExportDataTests : BaseTransformerTestClass { @@ -67,7 +67,7 @@ interface UIFeedbackGenerator : UIInteraction { [Theory] [AllSupportedPlatformsClassData] - public void TryeCreateTests (ApplePlatform platform, (string Source, string Path) source, ExportData expectedData) + void TryCreateTests (ApplePlatform platform, (string Source, string Path) source, ExportData expectedData) { // create a compilation used to create the transformer var compilation = CreateCompilation (platform, sources: source); diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/FieldDataTests.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/FieldDataTests.cs new file mode 100644 index 00000000000..3329a50a223 --- /dev/null +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/Attributes/FieldDataTests.cs @@ -0,0 +1,108 @@ +// 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 FieldDataTests : BaseTransformerTestClass { + + class TestDataTryCreate : IEnumerable { + public IEnumerator GetEnumerator () + { + const string symbolOnly = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV] +[MacCatalyst (13, 1)] +[DisableDefaultCtor] +[Abstract] +[BaseType (typeof (NSObject))] +interface UIFeedbackGenerator : UIInteraction { + + [Field (""prepare"")] + void Prepare { get; } +} +"; + yield return [(Source: symbolOnly, Path: "/some/random/path.cs"), new FieldData ("prepare")]; + + const string symbolAndLibrary = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV] +[MacCatalyst (13, 1)] +[DisableDefaultCtor] +[Abstract] +[BaseType (typeof (NSObject))] +interface UIFeedbackGenerator : UIInteraction { + + [Field (""prepare"", ""LibraryName"")] + void Prepare { get; } +} +"; + yield return [(Source: symbolAndLibrary, Path: "/some/random/path.cs"), new FieldData ("prepare", "LibraryName")]; + + const string symbolAndLibraryNamed = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV] +[MacCatalyst (13, 1)] +[DisableDefaultCtor] +[Abstract] +[BaseType (typeof (NSObject))] +interface UIFeedbackGenerator : UIInteraction { + + [Field (""prepare"", LibraryName = ""LibraryName"")] + void Prepare { get; } +} +"; + yield return [(Source: symbolAndLibraryNamed, Path: "/some/random/path.cs"), new FieldData ("prepare", "LibraryName")]; + } + + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); + } + + [Theory] + [AllSupportedPlatformsClassData] + void TryCreateTests (ApplePlatform platform, (string Source, string Path) source, FieldData expectedData) + { + // create a compilation used to create the transformer + var compilation = CreateCompilation (platform, sources: source); + var syntaxTree = compilation.SyntaxTrees.FirstOrDefault (); + Assert.NotNull (syntaxTree); + + var semanticModel = compilation.GetSemanticModel (syntaxTree); + Assert.NotNull (semanticModel); + + var declaration = syntaxTree.GetRoot () + .DescendantNodes ().OfType () + .FirstOrDefault (); + Assert.NotNull (declaration); + + var symbol = semanticModel.GetDeclaredSymbol (declaration); + Assert.NotNull (symbol); + var fieldData = symbol.GetAttribute (AttributesNames.FieldAttribute, FieldData.TryParse); + Assert.Equal (expectedData, fieldData); + } +}