From bb011fb7ea169e50aae3a48cf7d156da4ffa3589 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Saenz Date: Sun, 19 Jan 2025 14:30:38 -0500 Subject: [PATCH 1/3] [Rgen] Implement the filtering in the transformer tool. Allow the transformer to choose the topic for a base declaration by looking at the attribute data. --- .../Microsoft.Macios.Bindings.Analyzer.csproj | 4 +- ...nsions.cs => TypeSymbolExtensions.Core.cs} | 151 +--------- .../TypeSymbolExtensions.Generator.cs | 152 ++++++++++ .../AttributesNames.cs | 48 ++++ .../Microsoft.Macios.Transformer.csproj | 34 +++ .../Transformer.cs | 150 ++++++---- .../Workers/CategoryTransformer.cs | 26 +- .../Workers/ClassTransformer.cs | 16 +- .../Workers/CopyTransformer.cs | 34 +++ .../Workers/ErrorDomainTransformer.cs | 35 +++ .../Workers/ITransformer.cs | 12 + .../Workers/ProtocolTransformer.cs | 18 +- .../Workers/SmartEnumTransformer.cs | 19 +- .../Workers/StrongDictionaryTransformer.cs | 18 +- src/rgen/rgen.sln | 3 +- .../BaseTransformerTestClass.cs | 63 +++++ .../Microsoft.Macios.Transformer.Tests.csproj | 54 ++-- .../TransformerTests.cs | 266 ++++++++++++++++++ .../UnitTest1.cs | 11 - 19 files changed, 837 insertions(+), 277 deletions(-) rename src/rgen/Microsoft.Macios.Generator/Extensions/{TypeSymbolExtensions.cs => TypeSymbolExtensions.Core.cs} (59%) create mode 100644 src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs create mode 100644 src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs create mode 100644 src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs create mode 100644 src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs create mode 100644 src/rgen/Microsoft.Macios.Transformer/Workers/ITransformer.cs create mode 100644 tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs create mode 100644 tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs delete mode 100644 tests/rgen/Microsoft.Macios.Transformer.Tests/UnitTest1.cs diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj index 5a77c43cfbfb..7d22bfbe0dcb 100644 --- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj +++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj @@ -63,8 +63,8 @@ Generator/Extensions/CompilationExtensions.cs - - Generator/Extensions/TypeSymbolExtensions.cs + + Generator/Extensions/TypeSymbolExtensions.Core.cs Generator/Extensions/TypedConstantExtensions.cs diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs similarity index 59% rename from src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.cs rename to src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs index 7a2766ff02e1..a58dfb4b085a 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs @@ -1,19 +1,16 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; -using Microsoft.Macios.Generator.Attributes; -using Microsoft.Macios.Generator.Availability; namespace Microsoft.Macios.Generator.Extensions; -static class TypeSymbolExtensions { +static partial class TypeSymbolExtensions { /// /// 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. @@ -70,75 +67,7 @@ public static ImmutableArray GetParents (this ISymbol symbol) return [.. result]; } - - /// - /// Return the symbol availability WITHOUT taking into account the parent symbols availability. - /// - /// The symbols whose availability attributes we want to retrieve. - /// The symbol availability WITHOUT taking into account the parent symbols. - /// This is a helper method, you probably don't want to use it. - static SymbolAvailability GetAvailabilityForSymbol (this ISymbol symbol) - { - //get the attribute of the symbol and look for the Supported and Unsupported attributes and - // add the different platforms to the result hashsets - var builder = SymbolAvailability.CreateBuilder (); - var boundAttributes = symbol.GetAttributes (); - if (boundAttributes.Length == 0) { - // no attrs in the symbol, therefore the symbol is supported in all platforms - return builder.ToImmutable (); - } - - foreach (var attributeData in boundAttributes) { - var attrName = attributeData.AttributeClass?.ToDisplayString (); - if (string.IsNullOrEmpty (attrName)) - continue; - // we only care in this case about the support and unsupported attrs, ignore any other - switch (attrName) { - case AttributesNames.SupportedOSPlatformAttribute: - if (SupportedOSPlatformData.TryParse (attributeData, out var supportedPlatform)) { - builder.Add (supportedPlatform.Value); - } - - break; - case AttributesNames.UnsupportedOSPlatformAttribute: - if (UnsupportedOSPlatformData.TryParse (attributeData, out var unsupportedPlatform)) { - builder.Add (unsupportedPlatform.Value); - } - - break; - case AttributesNames.ObsoletedOSPlatformAttribute: - if (ObsoletedOSPlatformData.TryParse (attributeData, out var obsoletedOsPlatform)) { - builder.Add (obsoletedOsPlatform.Value); - } - - break; - default: - continue; - } - } - - return builder.ToImmutable (); - } - - /// - /// Returns the symbol availability taking into account the parent symbols availability. - /// - /// That means that the attributes used on the current symbol are merged with the attributes used - /// in all the symbol parents following the correct child-parent order. - /// - /// The symbol whose availability we want to retrieve. - /// A symbol availability structure for the symbol. - public static SymbolAvailability GetSupportedPlatforms (this ISymbol symbol) - { - var availability = GetAvailabilityForSymbol (symbol); - // get the parents and return the merge - foreach (var parent in GetParents (symbol)) { - availability = availability.MergeWithParent (GetAvailabilityForSymbol (parent)); - } - - return availability; - } - + public static bool HasAttribute (this ISymbol symbol, string attribute) { var boundAttributes = symbol.GetAttributes (); @@ -155,57 +84,7 @@ public static bool HasAttribute (this ISymbol symbol, string attribute) return false; } - - public static bool IsSmartEnum (this ITypeSymbol symbol) - { - // a type is a smart enum if its type is a enum one AND it was decorated with the - // binding type attribute - return symbol.TypeKind == TypeKind.Enum - && symbol.HasAttribute (AttributesNames.BindingAttribute); - } - - public static BindingTypeData GetBindingData (this ISymbol symbol) - { - var boundAttributes = symbol.GetAttributes (); - if (boundAttributes.Length == 0) { - // no attrs in the symbol, therefore the symbol is supported in all platforms - return default; - } - - // we are looking for the basic BindingAttribute attr - foreach (var attributeData in boundAttributes) { - var attrName = attributeData.AttributeClass?.ToDisplayString (); - if (string.IsNullOrEmpty (attrName) || attrName != AttributesNames.BindingAttribute) - continue; - if (BindingTypeData.TryParse (attributeData, out var bindingData)) { - return bindingData.Value; - } - } - - return default; - } - - public static BindingTypeData GetBindingData (this ISymbol symbol) where T : Enum - { - var boundAttributes = symbol.GetAttributes (); - if (boundAttributes.Length == 0) { - // no attrs in the symbol, therefore the symbol is supported in all platforms - return default; - } - - var targetAttrName = AttributesNames.GetBindingTypeAttributeName (); - foreach (var attributeData in boundAttributes) { - var attrName = attributeData.AttributeClass?.ToDisplayString (); - if (string.IsNullOrEmpty (attrName) || attrName != targetAttrName) - continue; - if (BindingTypeData.TryParse (attributeData, out var bindingData)) { - return bindingData.Value; - } - } - - return default; - } - + delegate string? GetAttributeNames (); delegate bool TryParse (AttributeData data, [NotNullWhen (true)] out T? value) where T : struct; @@ -234,29 +113,7 @@ public static BindingTypeData GetBindingData (this ISymbol symbol) where T return exportData.Value; return null; } - - /// - /// Retrieve the data of an export attribute on a symbol. - /// - /// The tagged symbol. - /// Enum type used in the attribute. - /// The data of the export attribute if present or null if it was not found. - /// If the passed enum is unknown or not supported as an enum for the export attribute, null will be - /// returned. - public static ExportData? GetExportData (this ISymbol symbol) where T : Enum - => GetAttribute> (symbol, AttributesNames.GetExportAttributeName, ExportData.TryParse); - - /// - /// Retrieve the data of a field attribute on a symbol. - /// - /// The tagged symbol. - /// Enum type used in the attribute. - /// The data of the export attribute if present or null if it was not found. - /// If the passed enum is unknown or not supported as an enum for the field attribute, null will be - /// returned. - public static FieldData? GetFieldData (this ISymbol symbol) where T : Enum - => GetAttribute> (symbol, AttributesNames.GetFieldAttributeName, FieldData.TryParse); - + /// /// Returns if a type is blittable or not. /// diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs new file mode 100644 index 000000000000..6101efc6d184 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using Microsoft.CodeAnalysis; +using Microsoft.Macios.Generator.Attributes; +using Microsoft.Macios.Generator.Availability; + +namespace Microsoft.Macios.Generator.Extensions; + +static partial class TypeSymbolExtensions { + + /// + /// Return the symbol availability WITHOUT taking into account the parent symbols availability. + /// + /// The symbols whose availability attributes we want to retrieve. + /// The symbol availability WITHOUT taking into account the parent symbols. + /// This is a helper method, you probably don't want to use it. + static SymbolAvailability GetAvailabilityForSymbol (this ISymbol symbol) + { + //get the attribute of the symbol and look for the Supported and Unsupported attributes and + // add the different platforms to the result hashsets + var builder = SymbolAvailability.CreateBuilder (); + var boundAttributes = symbol.GetAttributes (); + if (boundAttributes.Length == 0) { + // no attrs in the symbol, therefore the symbol is supported in all platforms + return builder.ToImmutable (); + } + + foreach (var attributeData in boundAttributes) { + var attrName = attributeData.AttributeClass?.ToDisplayString (); + if (string.IsNullOrEmpty (attrName)) + continue; + // we only care in this case about the support and unsupported attrs, ignore any other + switch (attrName) { + case AttributesNames.SupportedOSPlatformAttribute: + if (SupportedOSPlatformData.TryParse (attributeData, out var supportedPlatform)) { + builder.Add (supportedPlatform.Value); + } + + break; + case AttributesNames.UnsupportedOSPlatformAttribute: + if (UnsupportedOSPlatformData.TryParse (attributeData, out var unsupportedPlatform)) { + builder.Add (unsupportedPlatform.Value); + } + + break; + case AttributesNames.ObsoletedOSPlatformAttribute: + if (ObsoletedOSPlatformData.TryParse (attributeData, out var obsoletedOsPlatform)) { + builder.Add (obsoletedOsPlatform.Value); + } + + break; + default: + continue; + } + } + + return builder.ToImmutable (); + } + + /// + /// Returns the symbol availability taking into account the parent symbols availability. + /// + /// That means that the attributes used on the current symbol are merged with the attributes used + /// in all the symbol parents following the correct child-parent order. + /// + /// The symbol whose availability we want to retrieve. + /// A symbol availability structure for the symbol. + public static SymbolAvailability GetSupportedPlatforms (this ISymbol symbol) + { + var availability = GetAvailabilityForSymbol (symbol); + // get the parents and return the merge + foreach (var parent in GetParents (symbol)) { + availability = availability.MergeWithParent (GetAvailabilityForSymbol (parent)); + } + + return availability; + } + + public static bool IsSmartEnum (this ITypeSymbol symbol) + { + // a type is a smart enum if its type is a enum one AND it was decorated with the + // binding type attribute + return symbol.TypeKind == TypeKind.Enum + && symbol.HasAttribute (AttributesNames.BindingAttribute); + } + + public static BindingTypeData GetBindingData (this ISymbol symbol) + { + var boundAttributes = symbol.GetAttributes (); + if (boundAttributes.Length == 0) { + // no attrs in the symbol, therefore the symbol is supported in all platforms + return default; + } + + // we are looking for the basic BindingAttribute attr + foreach (var attributeData in boundAttributes) { + var attrName = attributeData.AttributeClass?.ToDisplayString (); + if (string.IsNullOrEmpty (attrName) || attrName != AttributesNames.BindingAttribute) + continue; + if (BindingTypeData.TryParse (attributeData, out var bindingData)) { + return bindingData.Value; + } + } + + return default; + } + + public static BindingTypeData GetBindingData (this ISymbol symbol) where T : Enum + { + var boundAttributes = symbol.GetAttributes (); + if (boundAttributes.Length == 0) { + // no attrs in the symbol, therefore the symbol is supported in all platforms + return default; + } + + var targetAttrName = AttributesNames.GetBindingTypeAttributeName (); + foreach (var attributeData in boundAttributes) { + var attrName = attributeData.AttributeClass?.ToDisplayString (); + if (string.IsNullOrEmpty (attrName) || attrName != targetAttrName) + continue; + if (BindingTypeData.TryParse (attributeData, out var bindingData)) { + return bindingData.Value; + } + } + + return default; + } + + /// + /// Retrieve the data of an export attribute on a symbol. + /// + /// The tagged symbol. + /// Enum type used in the attribute. + /// The data of the export attribute if present or null if it was not found. + /// If the passed enum is unknown or not supported as an enum for the export attribute, null will be + /// returned. + public static ExportData? GetExportData (this ISymbol symbol) where T : Enum + => GetAttribute> (symbol, AttributesNames.GetExportAttributeName, ExportData.TryParse); + + /// + /// Retrieve the data of a field attribute on a symbol. + /// + /// The tagged symbol. + /// Enum type used in the attribute. + /// The data of the export attribute if present or null if it was not found. + /// If the passed enum is unknown or not supported as an enum for the field attribute, null will be + /// returned. + public static FieldData? GetFieldData (this ISymbol symbol) where T : Enum + => GetAttribute> (symbol, AttributesNames.GetFieldAttributeName, FieldData.TryParse); +} diff --git a/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs b/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs new file mode 100644 index 000000000000..fc767cd8abde --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Macios.Transformer; + +static class AttributesNames { + public const string AbstractAttribute = "AbstractAttribute"; + public const string AdvancedAttribute = "AdvancedAttribute"; + public const string BackingFieldTypeAttribute = "BackingFieldTypeAttribute"; + public const string BaseTypeAttribute = "BaseTypeAttribute"; + public const string BindAttribute = "BindAttribute"; + public const string CategoryAttribute = "CategoryAttribute"; + public const string CoreImageFilterAttribute = "CoreImageFilterAttribute"; + public const string DefaultCtorVisibilityAttribute = "DefaultCtorVisibilityAttribute"; + public const string DeprecatedAttribute = "DeprecatedAttribute"; + public const string DesignatedDefaultCtorAttribute = "DesignatedDefaultCtorAttribute"; + public const string DisableDefaultCtorAttribute = "DisableDefaultCtorAttribute"; + public const string DisposeAttribute = "DisposeAttribute"; + public const string ErrorDomainAttribute = "ErrorDomainAttribute"; + public const string FieldAttribute = "Foundation.FieldAttribute"; + public const string AdviceAttribute = "Foundation.AdviceAttribute"; + public const string ModelAttribute = "Foundation.ModelAttribute"; + public const string ProtocolAttribute = "Foundation.ProtocolAttribute"; + public const string InternalAttribute = "InternalAttribute"; + public const string IntroducedAttribute = "IntroducedAttribute"; + public const string MacCatalystAttribute = "MacCatalystAttribute"; + public const string NoiOSAttribute = "NoiOSAttribute"; + public const string NoMacAttribute = "NoMacAttribute"; + public const string NoMacCatalystAttribute = "NoMacCatalystAttribute"; + public const string NoTVAttribute = "NoTVAttribute"; + public const string iOSAttribute = "ObjCRuntime.iOSAttribute"; + public const string MacAttribute = "ObjCRuntime.MacAttribute"; + public const string NativeAttribute = "ObjCRuntime.NativeAttribute"; + public const string NativeNameAttribute = "ObjCRuntime.NativeNameAttribute"; + public const string ObsoletedAttribute = "ObsoletedAttribute"; + public const string PartialAttribute = "PartialAttribute"; + public const string SealedAttribute = "SealedAttribute"; + public const string StaticAttribute = "StaticAttribute"; + public const string StrongDictionaryAttribute = "StrongDictionaryAttribute"; + public const string SyntheticAttribute = "SyntheticAttribute"; + public const string EditorBrowsableAttribute = "System.ComponentModel.EditorBrowsableAttribute"; + public const string ExperimentalAttribute = "System.Diagnostics.CodeAnalysis.ExperimentalAttribute"; + public const string FlagsAttribute = "System.FlagsAttribute"; + public const string ObsoleteAttribute = "System.ObsoleteAttribute"; + public const string ThreadSafeAttribute = "ThreadSafeAttribute"; + public const string TVAttribute = "TVAttribute"; + public const string UnavailableAttribute = "UnavailableAttribute"; +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj b/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj index 34893e627f28..3d0ac820d626 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj +++ b/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj @@ -15,4 +15,38 @@ + + + <_Parameter1>Microsoft.Macios.Transformer.Tests + + + + + + DictionaryComparer.cs + + + Attributes/ObsoletedOSPlatformData.cs + + + Attributes/SupportedOSPlatformData.cs + + + Attributes/UnsupportedOSPlatformData.cs + + + Availability/*.cs + + + Extensions/StringExtensions.cs + + + Extensions/TypeSymbolExtensions.Core.cs + + + + + + + diff --git a/src/rgen/Microsoft.Macios.Transformer/Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/Transformer.cs index c98314a37d6a..8279519a9eab 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Transformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Transformer.cs @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Text; using Marille; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Extensions; using Microsoft.Macios.Transformer.Extensions; using Microsoft.Macios.Transformer.Workers; @@ -17,19 +18,31 @@ namespace Microsoft.Macios.Transformer; /// to be able to process the different transformations per binding type. /// class Transformer { - string destinationDirectory; + readonly string destinationDirectory; readonly Compilation compilation; - readonly ImmutableArray sources; - HashSet? namespaceFilter; + readonly HashSet? namespaceFilter; + readonly Dictionary> transformers = new (); - internal Transformer (string destination, Compilation compilationResult, ImmutableArray syntaxTrees, - IEnumerable? namespaces = null) + internal Transformer (string destination, Compilation compilationResult, IEnumerable? namespaces = null) { destinationDirectory = destination; compilation = compilationResult; - sources = syntaxTrees; if (namespaces is not null) namespaceFilter = new HashSet (namespaces); + + ITransformer<(string Path, string SymbolName)> [] defaultTransformers = [ + new CategoryTransformer (destinationDirectory), + new ClassTransformer (destinationDirectory), + new ProtocolTransformer (destinationDirectory), + new SmartEnumTransformer (destinationDirectory), + new StrongDictionaryTransformer (destinationDirectory), + new CopyTransformer (destinationDirectory), + new ErrorDomainTransformer (destinationDirectory), + ]; + // init the dict of transformers to access them via the name of the class + foreach (var transformer in defaultTransformers) { + transformers.Add (transformer.GetType ().Name, transformer); + } } internal async Task CreateHub () @@ -38,25 +51,71 @@ internal async Task CreateHub () var hub = new Hub (); // use as many threads as the system allows - var topicConfiguration = new TopicConfiguration { Mode = ChannelDeliveryMode.AtLeastOnceSync }; - - // create the channels, because the app is alreay asyc there is nothing to deal with threads. - var categories = new CategoryTransformer (destinationDirectory); - await hub.CreateAsync (nameof (CategoryTransformer), topicConfiguration, categories, categories); + var configuration = new TopicConfiguration { Mode = ChannelDeliveryMode.AtLeastOnceSync }; + foreach (var (topicName, transformer) in transformers) { + await hub.CreateAsync (topicName, configuration, transformer, transformer); + } - var classes = new ClassTransformer (destinationDirectory); - await hub.CreateAsync (nameof (ClassTransformer), topicConfiguration, classes, classes); + return hub; + } - var protocols = new ProtocolTransformer (destinationDirectory); - await hub.CreateAsync (nameof (ProtocolTransformer), topicConfiguration, protocols, protocols); + internal static string? SelectTopic (INamedTypeSymbol symbol) + { + // get the attrs, based on those return the correct topic to use + var attrs = symbol.GetAttributeData (); + if (symbol.TypeKind == TypeKind.Enum) { + // simplest case, an error domain + if (attrs.ContainsKey (AttributesNames.ErrorDomainAttribute)) + return nameof(ErrorDomainTransformer); + + // in this case, we need to check if the enum is a smart enum. + // Smart enum: One of the enum members contains a FieldAttribute. Does NOT have to be ALL + var enumMembers = symbol.GetMembers ().OfType ().ToArray (); + foreach (var enumField in enumMembers) { + var fieldAttrs = enumField.GetAttributeData (); + if (fieldAttrs.ContainsKey (AttributesNames.FieldAttribute)) { + return nameof(SmartEnumTransformer); + } + } - var smartEnums = new SmartEnumTransformer (destinationDirectory); - await hub.CreateAsync (nameof (SmartEnumTransformer), topicConfiguration, smartEnums, smartEnums); + // we have either a native enum of a regular enum, we will use the copy worker + return nameof(CopyTransformer); + } + + if (attrs.ContainsKey (AttributesNames.BaseTypeAttribute)) { + // if can be a class or a protocol, check if the protocol attribute is present + if (attrs.ContainsKey (AttributesNames.ProtocolAttribute) || + attrs.ContainsKey (AttributesNames.ModelAttribute)) + return nameof(ProtocolTransformer); + if (attrs.ContainsKey (AttributesNames.CategoryAttribute)) + return nameof(CategoryTransformer); + return nameof(ClassTransformer); + } + + if (attrs.ContainsKey (AttributesNames.StrongDictionaryAttribute)) + return nameof(StrongDictionaryTransformer); - var strongDictionaries = new StrongDictionaryTransformer (destinationDirectory); - await hub.CreateAsync (nameof (StrongDictionaryTransformer), topicConfiguration, strongDictionaries, strongDictionaries); + return null; + } - return hub; + internal bool Skip (SyntaxTree syntaxTree, ISymbol symbol, [NotNullWhen (false)] out string? outputDirectory) + { + outputDirectory = null; + var symbolNamespace = symbol.ContainingNamespace.ToString (); + if (symbolNamespace is null) + // skip we could not retrieve the namespace + return true; + + if (namespaceFilter is not null && !namespaceFilter.Contains (symbolNamespace)) { + // TODO we could do this better by looking at the tree + Console.WriteLine ( + $"Skipping {symbol.Name} because namespace {symbolNamespace} was not included in the transformation"); + // filtered out + return true; + } + outputDirectory = Path.Combine (destinationDirectory, symbolNamespace); + // If the syntax tree comes from the output directory, we skip it because this is a manual binding + return syntaxTree.FilePath.StartsWith (outputDirectory); } internal async Task Execute () @@ -74,10 +133,10 @@ internal async Task Execute () var hub = await CreateHub (); // with the hub created, loop over the syntax trees and create the messages to be sent to the hub - foreach (var tree in sources) { + foreach (var tree in compilation.SyntaxTrees) { var model = compilation.GetSemanticModel (tree); // the bindings have A LOT of interfaces, we cannot get a symbol for the entire tree - var declarations = tree.GetRoot () + var declarations = (await tree.GetRootAsync ()) .DescendantNodes () .OfType ().ToArray (); @@ -91,31 +150,17 @@ internal async Task Execute () continue; } - var namespaceName = symbol.ContainingNamespace.ToString (); - if (namespaceName is null) - // skip we could not retrieve the namespace - continue; - - if (namespaceFilter is not null && !namespaceFilter.Contains (namespaceName)) { - // TODO we could do this better by looking at the tree - Console.WriteLine ($"Skipping {symbol.Name} because namespace {namespaceName} was not included in the transformation"); - // filtered out + if (Skip (tree, symbol, out var outputDirectory)) + // matched the filter continue; - } // create the destination directory if needed, this is the only location we should be creating directories - var currentDirectory = Path.Combine (destinationDirectory, namespaceName); - Directory.CreateDirectory (currentDirectory); - - var message = (tree.FilePath, symbol.Name); - // push the message to the hub, we are doing this to all channels, this will need to be filered in the - // future - Console.WriteLine ($"Publishing message to all channels: {message}"); - await hub.PublishAsync (nameof (CategoryTransformer), message); - await hub.PublishAsync (nameof (ClassTransformer), message); - await hub.PublishAsync (nameof (ProtocolTransformer), message); - await hub.PublishAsync (nameof (SmartEnumTransformer), message); - await hub.PublishAsync (nameof (StrongDictionaryTransformer), message); + Directory.CreateDirectory (outputDirectory); + + var topicName = SelectTopic (symbol); + if (topicName is not null && transformers.TryGetValue (topicName, out var transformer)) { + await hub.PublishAsync (topicName, transformer.CreateMessage (tree, symbol)); + } } } @@ -124,8 +169,8 @@ internal async Task Execute () await hub.CloseAllAsync (); } - - public static Task Execute (string destinationDirectory, string rspFile, string workingDirectory, string sdkDirectory) + public static Task Execute (string destinationDirectory, string rspFile, string workingDirectory, + string sdkDirectory) { Console.WriteLine ("Executing transformation"); // the transformation works as follows. We first need to parse the rsp file to create a compilation @@ -135,13 +180,13 @@ public static Task Execute (string destinationDirectory, string rspFile, string rspFile, workingDirectory, sdkDirectory); // add NET to the preprocessor directives - var preprocesorDirectives = parseResult.ParseOptions.PreprocessorSymbolNames.ToList (); - preprocesorDirectives.Add ("NET"); + var preprocessorDirectives = parseResult.ParseOptions.PreprocessorSymbolNames.ToList (); + preprocessorDirectives.Add ("NET"); // fixing the parsing options, we must have an issue in the rsp var updatedParseOptions = parseResult.ParseOptions .WithLanguageVersion (LanguageVersion.Latest) - .WithPreprocessorSymbols (preprocesorDirectives) + .WithPreprocessorSymbols (preprocessorDirectives) .WithDocumentationMode (DocumentationMode.None); var references = parseResult.GetReferences (workingDirectory, sdkDirectory); @@ -154,7 +199,7 @@ public static Task Execute (string destinationDirectory, string rspFile, string options: parseResult.CompilationOptions); var diagnostics = compilation.GetDiagnostics (); - Console.WriteLine ($"Diganostics legth {diagnostics.Length}"); + Console.WriteLine ($"Diagnostics length {diagnostics.Length}"); // collect all the compilation errors, ignoring the warnings, if any error is found, we throw an exception var errors = diagnostics.Where (d => d.Severity == DiagnosticSeverity.Error).ToArray (); if (errors.Length > 0) { @@ -162,12 +207,11 @@ public static Task Execute (string destinationDirectory, string rspFile, string foreach (var resultError in errors) { sb.AppendLine ($"{resultError}"); } - Console.WriteLine (sb); throw new Exception ($"Error during workspace compilation: {sb}"); } // create a new transformer with the compilation result and the syntax trees - var transformer = new Transformer (destinationDirectory, compilation, parsedSource); + var transformer = new Transformer (destinationDirectory, compilation); return transformer.Execute (); } } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs index 1c1e7ab391ed..1a8eaf992c87 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs @@ -2,26 +2,34 @@ // Licensed under the MIT License. using Marille; +using Microsoft.CodeAnalysis; namespace Microsoft.Macios.Transformer.Workers; -public class CategoryTransformer (string destinationDirectory) : IWorker<(string Path, string SymbolName)>, IErrorWorker<(string Path, string Example)> { - +public class CategoryTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { + + public bool UseBackgroundThread { get => true; } + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"CategoryTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - - public void Dispose () { } - - public ValueTask DisposeAsync () => ValueTask.CompletedTask; - - public Task ConsumeAsync ((string Path, string Example) message, Exception exception, + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + + public void Dispose () { } + + public ValueTask DisposeAsync () => ValueTask.CompletedTask; + - public bool UseBackgroundThread { get => true; } } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs index e37855567356..74eaa8c82a8b 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs @@ -2,26 +2,32 @@ // Licensed under the MIT License. using Marille; +using Microsoft.CodeAnalysis; namespace Microsoft.Macios.Transformer.Workers; -public class ClassTransformer (string destinationDirectory) : IWorker<(string Path, string SymbolName)>, IErrorWorker<(string Path, string Example)> { +public class ClassTransformer (string destinationDirectory ): ITransformer<(string Path, string SymbolName)> { + public ValueTask DisposeAsync () => ValueTask.CompletedTask; public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"ClassTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - - public Task ConsumeAsync ((string Path, string Example) message, Exception exception, + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + public void Dispose () { } - public ValueTask DisposeAsync () => ValueTask.CompletedTask; public bool UseBackgroundThread { get => true; } } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs new file mode 100644 index 000000000000..9923d96e7585 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Marille; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Macios.Transformer.Workers; + +public class CopyTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { + + public bool UseBackgroundThread { get => true; } + + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) + { + Console.WriteLine($"CopyTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); + return Task.Delay (10); + } + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, + CancellationToken token = new CancellationToken ()) + { + return Task.CompletedTask; + } + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + + public void Dispose () { } + + public ValueTask DisposeAsync () => ValueTask.CompletedTask; + +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs new file mode 100644 index 000000000000..4db5151ea6ec --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Marille; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Macios.Transformer.Workers; + + +public class ErrorDomainTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { + + public bool UseBackgroundThread { get => true; } + + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) + { + Console.WriteLine($"CopyTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); + return Task.Delay (10); + } + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, + CancellationToken token = new CancellationToken ()) + { + return Task.CompletedTask; + } + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + + public void Dispose () { } + + public ValueTask DisposeAsync () => ValueTask.CompletedTask; + +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ITransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ITransformer.cs new file mode 100644 index 000000000000..9f586727759d --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ITransformer.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Marille; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Macios.Transformer.Workers; + +interface ITransformer : IWorker, IErrorWorker where T : struct { + + T CreateMessage (SyntaxTree treeNode, ISymbol symbol); +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs index 07f71cf4e1fa..d710a7cd4919 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs @@ -2,26 +2,32 @@ // Licensed under the MIT License. using Marille; +using Microsoft.CodeAnalysis; namespace Microsoft.Macios.Transformer.Workers; -public class ProtocolTransformer (string destinationDirectory) : IWorker<(string Path, string SymbolName)>, IErrorWorker<(string Path, string Example)> { - +public class ProtocolTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { + + public bool UseBackgroundThread { get => true; } public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"ProtocolTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - - public Task ConsumeAsync ((string Path, string Example) message, Exception exception, + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; - public bool UseBackgroundThread { get => true; } } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs index b5f13dc964f5..ac62760e557f 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs @@ -2,26 +2,33 @@ // Licensed under the MIT License. using Marille; +using Microsoft.CodeAnalysis; namespace Microsoft.Macios.Transformer.Workers; -public class SmartEnumTransformer (string destinationDirectory) : IWorker<(string Path, string SymbolName)>, IErrorWorker<(string Path, string Example)> { - +public class SmartEnumTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { + + public bool UseBackgroundThread { get => true; } + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"SmartEnumTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - - public Task ConsumeAsync ((string Path, string Example) message, Exception exception, + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; - public bool UseBackgroundThread { get => true; } } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs index fbfcc1c7dc56..dcbc3dc643b4 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs @@ -2,26 +2,32 @@ // Licensed under the MIT License. using Marille; +using Microsoft.CodeAnalysis; namespace Microsoft.Macios.Transformer.Workers; -public class StrongDictionaryTransformer (string destinationDirectory) : IWorker<(string Path, string SymbolName)>, IErrorWorker<(string Path, string Example)> { - +public class StrongDictionaryTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { + + public bool UseBackgroundThread { get => true; } public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"StrongDictionaryTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - - public Task ConsumeAsync ((string Path, string Example) message, Exception exception, + + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) + { + return (treeNode.FilePath, symbol.Name); + } + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; - public bool UseBackgroundThread { get => true; } } diff --git a/src/rgen/rgen.sln b/src/rgen/rgen.sln index 12549b0432a6..cf0350504727 100644 --- a/src/rgen/rgen.sln +++ b/src/rgen/rgen.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# +# Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Macios.Generator", "Microsoft.Macios.Generator\Microsoft.Macios.Generator.csproj", "{8E9CF45D-E836-447E-9290-03A9CACE2704}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Macios.Generator.Sample", "Microsoft.Macios.Generator.Sample\Microsoft.Macios.Generator.Sample.csproj", "{AD0A1FDC-350F-47E2-AA9D-A6F32793C130}" @@ -18,6 +18,7 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Macios.Transformer", "Microsoft.Macios.Transformer\Microsoft.Macios.Transformer.csproj", "{D05D2AAA-71C9-49C9-B344-2F8C251E60DB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Macios.Transformer.Tests", "..\..\tests\rgen\Microsoft.Macios.Transformer.Tests\Microsoft.Macios.Transformer.Tests.csproj", "{BE23E467-7971-4439-BEE8-220B77F40027}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Macios.Bindings.CodeFixers", "Microsoft.Macios.Bindings.CodeFixers\Microsoft.Macios.Bindings.CodeFixers.csproj", "{4986D2E4-89B0-43A3-9879-93ED236C265D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Macios.Bindings.CodeFixers.Tests", "..\..\tests\rgen\Microsoft.Macios.Bindings.CodeFixers.Tests\Microsoft.Macios.Bindings.CodeFixers.Tests.csproj", "{E7928D64-8E45-40BF-B393-732FF20D35E7}" diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs new file mode 100644 index 000000000000..e17b4db221de --- /dev/null +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Xamarin.Tests; +using Xamarin.Utils; + +namespace Microsoft.Macios.Transformer.Tests; + +/// +/// Base class that allows to test the transformer. +/// +public class BaseTransformerTestClass { + + // list of the defines for each platform, this is passed to the parser to ensure that + // we are testing the platforms as if they were being compiled. + readonly Dictionary platformDefines = new () { + { ApplePlatform.iOS, new [] { "__IOS__" } }, + { ApplePlatform.TVOS, new [] { "__TVOS__" } }, + { ApplePlatform.MacOSX, new [] { "__MACOS__" } }, + { ApplePlatform.MacCatalyst, new [] { "__MACCATALYST__" } }, + }; + + protected Compilation CreateCompilation (ApplePlatform platform, [CallerMemberName] string name = "", params (string Source, string Path)[] sources) + { + // get the dotnet bcl and fully load it for the test. + var references = Directory.GetFiles (Configuration.DotNetBclDir, "*.dll") + .Select (assembly => MetadataReference.CreateFromFile (assembly)).ToList (); + + // get the dll for the current platform, this is needed because that way we will get the attributes that + // are used in the old dlls that are needed to test the transformer. + var targetFramework = TargetFramework.GetTargetFramework (platform, isDotNet: true); + var platformDll = Configuration.GetBaseLibrary (targetFramework); + if (!string.IsNullOrEmpty (platformDll)) { + references.Add (MetadataReference.CreateFromFile (platformDll)); + } else { + throw new InvalidOperationException ($"Could not find platform dll for {platform}"); + } + // include the bgen attributes to the compilation, otherwise the transformer will not work. + var sourcesList = sources.ToList (); + if (Configuration.TryGetRootPath (out var rootPath)) { + var oldVersionAttrs = Path.Combine (rootPath, "src", "ObjCRuntime", "PlatformAvailability.cs"); + sourcesList.Add ((File.ReadAllText(oldVersionAttrs), oldVersionAttrs)); + + var oldBgenAttrs = Path.Combine (rootPath, "src", "bgen", "Attributes.cs"); + sourcesList.Add ((File.ReadAllText(oldBgenAttrs), oldBgenAttrs)); + } + + var parseOptions = new CSharpParseOptions (LanguageVersion.Latest, DocumentationMode.None, preprocessorSymbols: ["COREBUILD"]); + var trees = sourcesList.Select ( + s => CSharpSyntaxTree.ParseText (s.Source, parseOptions, s.Path)) + .ToImmutableArray (); + + var options = new CSharpCompilationOptions (OutputKind.NetModule) + .WithAllowUnsafe (true); + + return CSharpCompilation.Create (name, trees, references, options); + } + +} diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/Microsoft.Macios.Transformer.Tests.csproj b/tests/rgen/Microsoft.Macios.Transformer.Tests/Microsoft.Macios.Transformer.Tests.csproj index e676a0a7b310..7ee72ccb9417 100644 --- a/tests/rgen/Microsoft.Macios.Transformer.Tests/Microsoft.Macios.Transformer.Tests.csproj +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/Microsoft.Macios.Transformer.Tests.csproj @@ -19,40 +19,32 @@ - + + - - external\Configuration.cs - - - external\ConfigurationXUnit.cs - - - external\Profile.cs - - - external\ExecutionHelper.cs - - - external\ApplePlatform.cs - - - external\TargetFramework.cs - - - external\StringUtils.cs - - - external\Execution.cs - - - external\SdkVersions.cs - - - external\Cache.cs - + + external\Configuration.cs + + + external\ConfigurationXUnit.cs + + + external\Profile.cs + + + external\ExecutionHelper.cs + + + external\StringUtils.cs + + + external\Execution.cs + + + external\Cache.cs + diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs new file mode 100644 index 000000000000..c3388c6c1b3a --- /dev/null +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs @@ -0,0 +1,266 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Transformer.Workers; +using Xamarin.Tests; +using Xamarin.Utils; + +namespace Microsoft.Macios.Transformer.Tests; + +public class TransformerTests : BaseTransformerTestClass, IDisposable { + string targetDirectory; + + public TransformerTests () + { + targetDirectory = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ()); + Directory.CreateDirectory (targetDirectory); + } + + + class TestDataSkipTests : IEnumerable { + public IEnumerator GetEnumerator () + { + const string sampleCode = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV] +[MacCatalyst (13, 1)] +[DisableDefaultCtor] +[Abstract] +[BaseType (typeof (NSObject))] +interface UIFeedbackGenerator : UIInteraction { + + [iOS (17, 5), MacCatalyst (17, 5)] + [Static] + [Export (""feedbackGeneratorForView:"")] + UIFeedbackGenerator GetFeedbackGenerator (UIView forView); + + [Export (""prepare"")] + void Prepare (); +} +"; + // correct path, not namespaces, do not skip and destination + yield return [(sampleCode, "/some/random/path.cs"), null!, false, "Test"]; + + // correct path, namespaces, do not skip and destination + yield return [(sampleCode, "/some/random/path.cs"), new [] { "Test" }, false, "Test"]; + + // correct path, namespaces, do not skip and destination + yield return [(sampleCode, "/some/random/path.cs"), new [] { "UIKit" }, true, null!]; + } + + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); + } + + [Theory] + [AllSupportedPlatformsClassData] + public void SkipTests (ApplePlatform platform, (string Source, string Path) source, string []? targetNamespaces, + bool expectedResult, string? expectedDestination) + { + // 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 transformer = new Transformer (targetDirectory, compilation, targetNamespaces); + if (expectedDestination is not null) + expectedDestination = Path.Combine (targetDirectory, expectedDestination); + Assert.Equal (expectedResult, transformer.Skip (syntaxTree, symbol, out var destination)); + Assert.Equal (expectedDestination, destination); + } + + class TestDataSelectTopicTests : IEnumerable { + public IEnumerator GetEnumerator () + { + const string path = "/path/to/source.cs"; + const string errorDomain = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV, NoMacCatalyst, iOS (18, 2)] +[ErrorDomain (""UIApplicationCategoryDefaultErrorDomain"")] +[Native] +public enum UIApplicationCategoryDefaultErrorCode : long { + RateLimited = 1, +} +"; + + yield return [(errorDomain, path), nameof(ErrorDomainTransformer)]; + + const string smartEnum = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +public enum UIAccessibilityTraits : long { + [Field (""UIAccessibilityTraitNone"")] + None, + + [Field (""UIAccessibilityTraitButton"")] + Button, + + [Field (""UIAccessibilityTraitLink"")] + Link, + + [Field (""UIAccessibilityTraitHeader"")] + Header, + + [Field (""UIAccessibilityTraitSearchField"")] + SearchField, +} +"; + + yield return [(smartEnum, path), nameof(SmartEnumTransformer)]; + + const string normalEnum = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +public enum UIAccessibilityTraits : long { + None, + Button, + Link, + Header, + SearchField, +} +"; + + yield return [(normalEnum, path), nameof(CopyTransformer)]; + + const string category = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[TV (18, 0), iOS (18, 0), MacCatalyst (18, 0)] +[Category] +[BaseType (typeof (NSObject))] +interface NSObject_UIAccessibilityHitTest { + [Export (""accessibilityHitTest:withEvent:"")] + [return: NullAllowed] + NSObject AccessibilityHitTest (CGPoint point, [NullAllowed] UIEvent withEvent); +} +"; + + yield return [(category, path), nameof(CategoryTransformer)]; + + const string baseType = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[TV (18, 0), iOS (18, 0), MacCatalyst (18, 0)] +[BaseType (typeof (NSObject))] +interface UIZoomTransitionInteractionContext { + [Export (""location"")] + CGPoint Location { get; } + + [Export (""velocity"")] + CGVector Velocity { get; } + + [Export (""willBegin"")] + bool WillBegin { get; } +} +"; + + yield return [(baseType, path), nameof(ClassTransformer)]; + + const string protocol = @" +using System; +using Foundation; +using ObjCRuntime; +using UIKit; + +namespace Test; + +[NoTV, NoMacCatalyst, iOS (18, 0)] +[Protocol (BackwardsCompatibleCodeGeneration = false), Model] +[BaseType (typeof (NSObject))] +interface UITextFormattingViewControllerDelegate { + [Abstract] + [Export (""textFormattingViewController:didChangeValue:"")] + void DidChangeValue (UITextFormattingViewController viewController, UITextFormattingViewControllerChangeValue changeValue); + + [Export (""textFormattingViewController:shouldPresentFontPicker:"")] + bool ShouldPresentFontPicker (UITextFormattingViewController viewController, UIFontPickerViewController fontPicker); + + [Export (""textFormattingViewController:shouldPresentColorPicker:"")] + bool ShouldPresentColorPicker (UITextFormattingViewController viewController, UIColorPickerViewController colorPicker); + + [Export (""textFormattingDidFinish:"")] + void TextFormattingDidFinish (UITextFormattingViewController viewController); +} +"; + + yield return [(protocol, path), nameof(ProtocolTransformer)]; + } + + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); + } + + [Theory] + [AllSupportedPlatformsClassData] + public void SelectTopicTests (ApplePlatform platform, (string Source, string Path) source, string expectedTopic) + { + // 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); + + // there is not need for a transformer, we are just testing the topic selection + Assert.Equal (expectedTopic, Transformer.SelectTopic (symbol)); + } + + public void Dispose () + { + // remove the temporary directory + Directory.Delete (targetDirectory, recursive: true); + } +} diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/UnitTest1.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/UnitTest1.cs deleted file mode 100644 index 327ca91936b7..000000000000 --- a/tests/rgen/Microsoft.Macios.Transformer.Tests/UnitTest1.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -namespace Microsoft.Macios.Transformer.Tests; - -public class UnitTest1 { - [Fact] - public void Test1 () - { - Assert.True (true); - } -} From 4cae16e32b08f3f3dcd4985b92dabcbdcf286b41 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Sun, 19 Jan 2025 14:52:38 -0500 Subject: [PATCH 2/3] IDE trying to be win32. --- .../Microsoft.Macios.Bindings.Analyzer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj index 7d22bfbe0dcb..50e69ddd6a51 100644 --- a/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj +++ b/src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj @@ -63,7 +63,7 @@ Generator/Extensions/CompilationExtensions.cs - + Generator/Extensions/TypeSymbolExtensions.Core.cs From b746a7d51f9870f778331cc4b0d375418141c5fa Mon Sep 17 00:00:00 2001 From: GitHub Actions Autoformatter Date: Sun, 19 Jan 2025 19:53:46 +0000 Subject: [PATCH 3/3] Auto-format source code --- .../Extensions/TypeSymbolExtensions.Core.cs | 6 +++--- .../TypeSymbolExtensions.Generator.cs | 8 ++++---- .../Transformer.cs | 20 +++++++++---------- .../Workers/CategoryTransformer.cs | 10 +++++----- .../Workers/ClassTransformer.cs | 8 ++++---- .../Workers/CopyTransformer.cs | 14 ++++++------- .../Workers/ErrorDomainTransformer.cs | 14 ++++++------- .../Workers/ProtocolTransformer.cs | 10 +++++----- .../Workers/SmartEnumTransformer.cs | 12 +++++------ .../Workers/StrongDictionaryTransformer.cs | 10 +++++----- .../BaseTransformerTestClass.cs | 12 +++++------ .../TransformerTests.cs | 14 ++++++------- 12 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs index a58dfb4b085a..57eaf4288168 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs @@ -67,7 +67,7 @@ public static ImmutableArray GetParents (this ISymbol symbol) return [.. result]; } - + public static bool HasAttribute (this ISymbol symbol, string attribute) { var boundAttributes = symbol.GetAttributes (); @@ -84,7 +84,7 @@ public static bool HasAttribute (this ISymbol symbol, string attribute) return false; } - + delegate string? GetAttributeNames (); delegate bool TryParse (AttributeData data, [NotNullWhen (true)] out T? value) where T : struct; @@ -113,7 +113,7 @@ public static bool HasAttribute (this ISymbol symbol, string attribute) return exportData.Value; return null; } - + /// /// Returns if a type is blittable or not. /// diff --git a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs index 6101efc6d184..70d64b650396 100644 --- a/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs +++ b/src/rgen/Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Generator.cs @@ -9,7 +9,7 @@ namespace Microsoft.Macios.Generator.Extensions; static partial class TypeSymbolExtensions { - + /// /// Return the symbol availability WITHOUT taking into account the parent symbols availability. /// @@ -58,7 +58,7 @@ static SymbolAvailability GetAvailabilityForSymbol (this ISymbol symbol) return builder.ToImmutable (); } - + /// /// Returns the symbol availability taking into account the parent symbols availability. /// @@ -77,7 +77,7 @@ public static SymbolAvailability GetSupportedPlatforms (this ISymbol symbol) return availability; } - + public static bool IsSmartEnum (this ITypeSymbol symbol) { // a type is a smart enum if its type is a enum one AND it was decorated with the @@ -127,7 +127,7 @@ public static BindingTypeData GetBindingData (this ISymbol symbol) where T return default; } - + /// /// Retrieve the data of an export attribute on a symbol. /// diff --git a/src/rgen/Microsoft.Macios.Transformer/Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/Transformer.cs index 8279519a9eab..fa653a299ab3 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Transformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Transformer.cs @@ -66,7 +66,7 @@ internal async Task CreateHub () if (symbol.TypeKind == TypeKind.Enum) { // simplest case, an error domain if (attrs.ContainsKey (AttributesNames.ErrorDomainAttribute)) - return nameof(ErrorDomainTransformer); + return nameof (ErrorDomainTransformer); // in this case, we need to check if the enum is a smart enum. // Smart enum: One of the enum members contains a FieldAttribute. Does NOT have to be ALL @@ -74,26 +74,26 @@ internal async Task CreateHub () foreach (var enumField in enumMembers) { var fieldAttrs = enumField.GetAttributeData (); if (fieldAttrs.ContainsKey (AttributesNames.FieldAttribute)) { - return nameof(SmartEnumTransformer); + return nameof (SmartEnumTransformer); } } // we have either a native enum of a regular enum, we will use the copy worker - return nameof(CopyTransformer); + return nameof (CopyTransformer); } - + if (attrs.ContainsKey (AttributesNames.BaseTypeAttribute)) { // if can be a class or a protocol, check if the protocol attribute is present if (attrs.ContainsKey (AttributesNames.ProtocolAttribute) || - attrs.ContainsKey (AttributesNames.ModelAttribute)) - return nameof(ProtocolTransformer); + attrs.ContainsKey (AttributesNames.ModelAttribute)) + return nameof (ProtocolTransformer); if (attrs.ContainsKey (AttributesNames.CategoryAttribute)) - return nameof(CategoryTransformer); - return nameof(ClassTransformer); + return nameof (CategoryTransformer); + return nameof (ClassTransformer); } - + if (attrs.ContainsKey (AttributesNames.StrongDictionaryAttribute)) - return nameof(StrongDictionaryTransformer); + return nameof (StrongDictionaryTransformer); return null; } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs index 1a8eaf992c87..86f1adb02c00 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/CategoryTransformer.cs @@ -7,26 +7,26 @@ namespace Microsoft.Macios.Transformer.Workers; public class CategoryTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { - + public bool UseBackgroundThread { get => true; } - + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"CategoryTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs index 74eaa8c82a8b..1cf6367e9da0 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ClassTransformer.cs @@ -6,7 +6,7 @@ namespace Microsoft.Macios.Transformer.Workers; -public class ClassTransformer (string destinationDirectory ): ITransformer<(string Path, string SymbolName)> { +public class ClassTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { public ValueTask DisposeAsync () => ValueTask.CompletedTask; public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) @@ -14,18 +14,18 @@ public class ClassTransformer (string destinationDirectory ): ITransformer<(stri Console.WriteLine ($"ClassTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs index 9923d96e7585..fcff0f2a3844 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/CopyTransformer.cs @@ -6,27 +6,27 @@ namespace Microsoft.Macios.Transformer.Workers; -public class CopyTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { - +public class CopyTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { + public bool UseBackgroundThread { get => true; } - + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { - Console.WriteLine($"CopyTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); + Console.WriteLine ($"CopyTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs index 4db5151ea6ec..73c2c579cb97 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ErrorDomainTransformer.cs @@ -7,27 +7,27 @@ namespace Microsoft.Macios.Transformer.Workers; -public class ErrorDomainTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { - +public class ErrorDomainTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { + public bool UseBackgroundThread { get => true; } - + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { - Console.WriteLine($"CopyTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); + Console.WriteLine ($"CopyTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs index d710a7cd4919..7032f8e853ba 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/ProtocolTransformer.cs @@ -6,26 +6,26 @@ namespace Microsoft.Macios.Transformer.Workers; -public class ProtocolTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { - +public class ProtocolTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { + public bool UseBackgroundThread { get => true; } public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"ProtocolTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs index ac62760e557f..f04d83c41314 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/SmartEnumTransformer.cs @@ -6,27 +6,27 @@ namespace Microsoft.Macios.Transformer.Workers; -public class SmartEnumTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { - +public class SmartEnumTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { + public bool UseBackgroundThread { get => true; } - + public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"SmartEnumTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; diff --git a/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs b/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs index dcbc3dc643b4..287ba445a5b7 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs +++ b/src/rgen/Microsoft.Macios.Transformer/Workers/StrongDictionaryTransformer.cs @@ -6,26 +6,26 @@ namespace Microsoft.Macios.Transformer.Workers; -public class StrongDictionaryTransformer (string destinationDirectory): ITransformer<(string Path, string SymbolName)> { - +public class StrongDictionaryTransformer (string destinationDirectory) : ITransformer<(string Path, string SymbolName)> { + public bool UseBackgroundThread { get => true; } public Task ConsumeAsync ((string Path, string SymbolName) message, CancellationToken token = new ()) { Console.WriteLine ($"StrongDictionaryTransformer: Transforming class {message.SymbolName} for path {message.Path} to {destinationDirectory}"); return Task.Delay (10); } - + public Task ConsumeAsync ((string Path, string SymbolName) message, Exception exception, CancellationToken token = new CancellationToken ()) { return Task.CompletedTask; } - + public (string Path, string SymbolName) CreateMessage (SyntaxTree treeNode, ISymbol symbol) { return (treeNode.FilePath, symbol.Name); } - + public void Dispose () { } public ValueTask DisposeAsync () => ValueTask.CompletedTask; diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs index e17b4db221de..2ec6c8e0a226 100644 --- a/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/BaseTransformerTestClass.cs @@ -14,7 +14,7 @@ namespace Microsoft.Macios.Transformer.Tests; /// Base class that allows to test the transformer. /// public class BaseTransformerTestClass { - + // list of the defines for each platform, this is passed to the parser to ensure that // we are testing the platforms as if they were being compiled. readonly Dictionary platformDefines = new () { @@ -24,12 +24,12 @@ public class BaseTransformerTestClass { { ApplePlatform.MacCatalyst, new [] { "__MACCATALYST__" } }, }; - protected Compilation CreateCompilation (ApplePlatform platform, [CallerMemberName] string name = "", params (string Source, string Path)[] sources) + protected Compilation CreateCompilation (ApplePlatform platform, [CallerMemberName] string name = "", params (string Source, string Path) [] sources) { // get the dotnet bcl and fully load it for the test. var references = Directory.GetFiles (Configuration.DotNetBclDir, "*.dll") .Select (assembly => MetadataReference.CreateFromFile (assembly)).ToList (); - + // get the dll for the current platform, this is needed because that way we will get the attributes that // are used in the old dlls that are needed to test the transformer. var targetFramework = TargetFramework.GetTargetFramework (platform, isDotNet: true); @@ -43,10 +43,10 @@ protected Compilation CreateCompilation (ApplePlatform platform, [CallerMemberNa var sourcesList = sources.ToList (); if (Configuration.TryGetRootPath (out var rootPath)) { var oldVersionAttrs = Path.Combine (rootPath, "src", "ObjCRuntime", "PlatformAvailability.cs"); - sourcesList.Add ((File.ReadAllText(oldVersionAttrs), oldVersionAttrs)); - + sourcesList.Add ((File.ReadAllText (oldVersionAttrs), oldVersionAttrs)); + var oldBgenAttrs = Path.Combine (rootPath, "src", "bgen", "Attributes.cs"); - sourcesList.Add ((File.ReadAllText(oldBgenAttrs), oldBgenAttrs)); + sourcesList.Add ((File.ReadAllText (oldBgenAttrs), oldBgenAttrs)); } var parseOptions = new CSharpParseOptions (LanguageVersion.Latest, DocumentationMode.None, preprocessorSymbols: ["COREBUILD"]); diff --git a/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs b/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs index c3388c6c1b3a..3d573705138c 100644 --- a/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs +++ b/tests/rgen/Microsoft.Macios.Transformer.Tests/TransformerTests.cs @@ -108,8 +108,8 @@ public enum UIApplicationCategoryDefaultErrorCode : long { } "; - yield return [(errorDomain, path), nameof(ErrorDomainTransformer)]; - + yield return [(errorDomain, path), nameof (ErrorDomainTransformer)]; + const string smartEnum = @" using System; using Foundation; @@ -136,7 +136,7 @@ public enum UIAccessibilityTraits : long { } "; - yield return [(smartEnum, path), nameof(SmartEnumTransformer)]; + yield return [(smartEnum, path), nameof (SmartEnumTransformer)]; const string normalEnum = @" using System; @@ -155,7 +155,7 @@ public enum UIAccessibilityTraits : long { } "; - yield return [(normalEnum, path), nameof(CopyTransformer)]; + yield return [(normalEnum, path), nameof (CopyTransformer)]; const string category = @" using System; @@ -175,7 +175,7 @@ interface NSObject_UIAccessibilityHitTest { } "; - yield return [(category, path), nameof(CategoryTransformer)]; + yield return [(category, path), nameof (CategoryTransformer)]; const string baseType = @" using System; @@ -199,7 +199,7 @@ interface UIZoomTransitionInteractionContext { } "; - yield return [(baseType, path), nameof(ClassTransformer)]; + yield return [(baseType, path), nameof (ClassTransformer)]; const string protocol = @" using System; @@ -228,7 +228,7 @@ interface UITextFormattingViewControllerDelegate { } "; - yield return [(protocol, path), nameof(ProtocolTransformer)]; + yield return [(protocol, path), nameof (ProtocolTransformer)]; } IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();