diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.Generator.cs new file mode 100644 index 00000000000..9462f7a4fe8 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.Generator.cs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.Macios.Generator.Attributes; +using Microsoft.Macios.Generator.Availability; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Accessor { + + /// + /// The data of the field attribute used to mark the value as a property binding. + /// + public ExportData? ExportPropertyData { get; init; } + + public bool MarshalNativeExceptions + => ExportPropertyData is not null && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions); + + /// + /// Create a new code change in a property accessor. + /// + /// The kind of accessor. + /// The os availability of the symbol. + /// The data of the export attribute found in the accessor. + /// The list of attributes attached to the accessor. + /// The list of visibility modifiers of the accessor. + public Accessor (AccessorKind accessorKind, + SymbolAvailability symbolAvailability, + ExportData? exportPropertyData, + ImmutableArray attributes, + ImmutableArray modifiers) + { + Kind = accessorKind; + SymbolAvailability = symbolAvailability; + ExportPropertyData = exportPropertyData; + Attributes = attributes; + Modifiers = modifiers; + } + + /// + /// Retrieve the selector to be used with the associated property. + /// + /// The property associated with the accessor. + /// The selector to use for the accessor. + public string? GetSelector (in Property associatedProperty) + { + // this is not a property but a field, we cannot retrieve a selector. + if (!associatedProperty.IsProperty) + return null; + + // There are two possible cases, the current accessor has an export attribute, if that + // is the case, we will use the selector in that attribute. Otherwise, we have: + // + // * getter: return the property selector. + // * setter: use the registrar code (it has the right logic) to get the setter. + if (ExportPropertyData is null) { + return Kind == AccessorKind.Getter + ? associatedProperty.ExportPropertyData.Value.Selector + : Registrar.Registrar.CreateSetterSelector (associatedProperty.ExportPropertyData.Value.Selector); + } + + return ExportPropertyData.Value.Selector; + } + + /// + /// Returns if the accessor should marshal native exceptions with the associated property. + /// + /// The property associated with the accessor. + /// True if either the accessor or the property were marked with the MarshalNativeExceptions flag. + public bool ShouldMarshalNativeExceptions (in Property property) + => MarshalNativeExceptions || property.MarshalNativeExceptions; + +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs index 5199718f4bd..bc4c0731bef 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Accessor.cs @@ -3,14 +3,15 @@ using System; using System.Collections.Immutable; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.Availability; namespace Microsoft.Macios.Generator.DataModel; -readonly struct Accessor : IEquatable { +[StructLayout (LayoutKind.Auto)] +readonly partial struct Accessor : IEquatable { /// /// The kind of accessor. /// @@ -21,14 +22,6 @@ namespace Microsoft.Macios.Generator.DataModel; /// public SymbolAvailability SymbolAvailability { get; } - /// - /// The data of the field attribute used to mark the value as a property binding. - /// - public ExportData? ExportPropertyData { get; init; } - - public bool MarshalNativeExceptions - => ExportPropertyData is not null && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions); - /// /// List of attribute code changes of the accessor. /// @@ -39,60 +32,6 @@ public bool MarshalNativeExceptions /// public ImmutableArray Modifiers { get; } - /// - /// Create a new code change in a property accessor. - /// - /// The kind of accessor. - /// The os availability of the symbol. - /// The data of the export attribute found in the accessor. - /// The list of attributes attached to the accessor. - /// The list of visibility modifiers of the accessor. - public Accessor (AccessorKind accessorKind, - SymbolAvailability symbolAvailability, - ExportData? exportPropertyData, - ImmutableArray attributes, - ImmutableArray modifiers) - { - Kind = accessorKind; - SymbolAvailability = symbolAvailability; - ExportPropertyData = exportPropertyData; - Attributes = attributes; - Modifiers = modifiers; - } - - /// - /// Retrieve the selector to be used with the associated property. - /// - /// The property associated with the accessor. - /// The selector to use for the accessor. - public string? GetSelector (in Property associatedProperty) - { - // this is not a property but a field, we cannot retrieve a selector. - if (!associatedProperty.IsProperty) - return null; - - // There are two possible cases, the current accessor has an export attribute, if that - // is the case, we will use the selector in that attribute. Otherwise, we have: - // - // * getter: return the property selector. - // * setter: use the registrar code (it has the right logic) to get the setter. - if (ExportPropertyData is null) { - return Kind == AccessorKind.Getter - ? associatedProperty.ExportPropertyData.Value.Selector - : Registrar.Registrar.CreateSetterSelector (associatedProperty.ExportPropertyData.Value.Selector); - } - - return ExportPropertyData.Value.Selector; - } - - /// - /// Returns if the accessor should marshal native exceptions with the associated property. - /// - /// The property associated with the accessor. - /// True if either the accessor or the property were marked with the MarshalNativeExceptions flag. - public bool ShouldMarshalNativeExceptions (in Property property) - => MarshalNativeExceptions || property.MarshalNativeExceptions; - /// public bool Equals (Accessor other) { diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.Generator.cs new file mode 100644 index 00000000000..7f63af7a425 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.Generator.cs @@ -0,0 +1,287 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Availability; +using Microsoft.Macios.Generator.Context; +using Microsoft.Macios.Generator.Extensions; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct CodeChanges { + + /// + /// Represents the type of binding that the code changes are for. + /// + public BindingType BindingType => BindingInfo.BindingType; + + readonly BindingInfo bindingInfo = default; + /// + /// Represents the binding data that will be used to generate the code. + /// + public BindingInfo BindingInfo => bindingInfo; + + /// + /// Returns all the library names and paths that are needed by the native code represented by the code change. + /// + public IEnumerable<(string LibraryName, string? LibraryPath)> LibraryPaths { + get { + // we want to return unique values, A library name should always point to the + // same library path (either null or with a value). We keep track of the ones we already + // returned in a set and skip if we already returned it. + var visited = new HashSet (); + + // return those libs needed by smart enums + foreach (var enumMember in EnumMembers) { + if (enumMember.FieldInfo is null) + continue; + var (_, libraryName, libraryPath) = enumMember.FieldInfo.Value; + if (visited.Add (libraryName)) // if already visited, we cannot add it + yield return (libraryName, libraryPath); + } + + // return those libs needed by field properties + foreach (var property in Properties) { + if (property.ExportFieldData is null) + continue; + var (_, libraryName, libraryPath) = property.ExportFieldData.Value; + if (visited.Add (libraryName)) // if already visited, we cannot add it + yield return (libraryName, libraryPath); + } + } + } + + /// + /// Decide if an enum value should be ignored as a change. + /// + /// The enum declaration under test. + /// The semantic model of the compilation. + /// True if the enum value should be ignored. False otherwise. + internal static bool Skip (EnumMemberDeclarationSyntax enumMemberDeclarationSyntax, SemanticModel semanticModel) + { + // for smart enums, we are only interested in the field that has a Field attribute + return !enumMemberDeclarationSyntax.HasAttribute (semanticModel, AttributesNames.EnumFieldAttribute); + } + + /// + /// Decide if a property should be ignored as a change. + /// + /// The property declaration under test. + /// The semantic model of the compilation. + /// True if the property should be ignored. False otherwise. + internal static bool Skip (PropertyDeclarationSyntax propertyDeclarationSyntax, SemanticModel semanticModel) + { + // valid properties are: + // 1. Partial + // 2. One of the following: + // 1. Field properties + // 2. Exported properties + if (propertyDeclarationSyntax.Modifiers.Any (SyntaxKind.PartialKeyword)) { + return !propertyDeclarationSyntax.HasAtLeastOneAttribute (semanticModel, + AttributesNames.FieldPropertyAttribute, AttributesNames.ExportPropertyAttribute); + } + + return true; + } + + internal static bool Skip (ConstructorDeclarationSyntax constructorDeclarationSyntax, SemanticModel semanticModel) + { + // TODO: we need to confirm this when we have support from the roslyn team. + return false; + } + + internal static bool Skip (EventDeclarationSyntax eventDeclarationSyntax, SemanticModel semanticModel) + { + // TODO: we need to confirm this when we have support from the roslyn team. + return false; + } + + internal static bool Skip (MethodDeclarationSyntax methodDeclarationSyntax, SemanticModel semanticModel) + { + // Valid methods are: + // 1. Partial + // 2. Contain the export attribute + if (methodDeclarationSyntax.Modifiers.Any (SyntaxKind.PartialKeyword)) { + return !methodDeclarationSyntax.HasAttribute (semanticModel, AttributesNames.ExportMethodAttribute); + } + + return true; + } + + delegate bool SkipDelegate (T declarationSyntax, SemanticModel semanticModel); + + delegate bool TryCreateDelegate (T declaration, RootBindingContext context, + [NotNullWhen (true)] out TR? change) + where T : MemberDeclarationSyntax + where TR : struct; + + static void GetMembers (TypeDeclarationSyntax baseDeclarationSyntax, RootBindingContext context, + SkipDelegate skip, TryCreateDelegate tryCreate, out ImmutableArray members) + where T : MemberDeclarationSyntax + where TR : struct + { + var bucket = ImmutableArray.CreateBuilder (); + var declarations = baseDeclarationSyntax.Members.OfType (); + foreach (var declaration in declarations) { + if (skip (declaration, context.SemanticModel)) + continue; + if (tryCreate (declaration, context, out var change)) + bucket.Add (change.Value); + } + + members = bucket.ToImmutable (); + } + + /// + /// Internal constructor added for testing purposes. + /// + /// The binding data of binding for the given code changes. + /// The name of the named type that created the code change. + /// The namespace that contains the named type. + /// The fully qualified name of the symbol. + /// The platform availability of the named symbol. + internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray @namespace, + string fullyQualifiedSymbol, SymbolAvailability symbolAvailability) + { + this.bindingInfo = bindingInfo; + this.name = name; + this.namespaces = @namespace; + FullyQualifiedSymbol = fullyQualifiedSymbol; + this.availability = symbolAvailability; + } + + /// + /// Creates a new instance of the struct for a given enum declaration. + /// + /// The enum declaration that triggered the change. + /// The root binding context of the current compilation. + CodeChanges (EnumDeclarationSyntax enumDeclaration, RootBindingContext context) + { + context.SemanticModel.GetSymbolData ( + declaration: enumDeclaration, + bindingType: BindingType.SmartEnum, + name: out name, + baseClass: out baseClass, + interfaces: out interfaces, + namespaces: out namespaces, + symbolAvailability: out availability, + bindingInfo: out bindingInfo); + FullyQualifiedSymbol = enumDeclaration.GetFullyQualifiedIdentifier (); + Attributes = enumDeclaration.GetAttributeCodeChanges (context.SemanticModel); + UsingDirectives = enumDeclaration.SyntaxTree.CollectUsingStatements (); + Modifiers = [.. enumDeclaration.Modifiers]; + var bucket = ImmutableArray.CreateBuilder (); + // loop over the fields and add those that contain a FieldAttribute + var enumValueDeclarations = enumDeclaration.Members.OfType (); + foreach (var enumValueDeclaration in enumValueDeclarations) { + if (Skip (enumValueDeclaration, context.SemanticModel)) + continue; + if (context.SemanticModel.GetDeclaredSymbol (enumValueDeclaration) is not IFieldSymbol enumValueSymbol) { + continue; + } + + var fieldData = enumValueSymbol.GetFieldData (); + // try and compute the library for this enum member + if (fieldData is null || !context.TryComputeLibraryName (fieldData.Value.LibraryName, Namespace [^1], + out string? libraryName, out string? libraryPath)) + // could not calculate the library for the enum, do not add it + continue; + var enumMember = new EnumMember ( + name: enumValueDeclaration.Identifier.ToFullString ().Trim (), + libraryName: libraryName, + libraryPath: libraryPath, + fieldData: enumValueSymbol.GetFieldData (), + symbolAvailability: enumValueSymbol.GetSupportedPlatforms (), + attributes: enumValueDeclaration.GetAttributeCodeChanges (context.SemanticModel) + ); + bucket.Add (enumMember); + } + + EnumMembers = bucket.ToImmutable (); + } + + /// + /// Creates a new instance of the struct for a given class declaration. + /// + /// The class declaration that triggered the change. + /// The root binding context of the current compilation. + CodeChanges (ClassDeclarationSyntax classDeclaration, RootBindingContext context) + { + context.SemanticModel.GetSymbolData ( + declaration: classDeclaration, + bindingType: BindingType.Class, + name: out name, + baseClass: out baseClass, + interfaces: out interfaces, + namespaces: out namespaces, + symbolAvailability: out availability, + bindingInfo: out bindingInfo); + FullyQualifiedSymbol = classDeclaration.GetFullyQualifiedIdentifier (); + Attributes = classDeclaration.GetAttributeCodeChanges (context.SemanticModel); + UsingDirectives = classDeclaration.SyntaxTree.CollectUsingStatements (); + Modifiers = [.. classDeclaration.Modifiers]; + + // use the generic method to get the members, we are using an out param to try an minimize the number of times + // the value types are copied + GetMembers (classDeclaration, context, Skip, + Constructor.TryCreate, out constructors); + GetMembers (classDeclaration, context, Skip, Property.TryCreate, + out properties); + GetMembers (classDeclaration, context, Skip, Event.TryCreate, out events); + GetMembers (classDeclaration, context, Skip, Method.TryCreate, + out methods); + } + + /// + /// Creates a new instance of the struct for a given interface declaration. + /// + /// The interface declaration that triggered the change. + /// The root binding context of the current compilation. + CodeChanges (InterfaceDeclarationSyntax interfaceDeclaration, RootBindingContext context) + { + context.SemanticModel.GetSymbolData ( + declaration: interfaceDeclaration, + bindingType: BindingType.Protocol, + name: out name, + baseClass: out baseClass, + interfaces: out interfaces, + namespaces: out namespaces, + symbolAvailability: out availability, + bindingInfo: out bindingInfo); + FullyQualifiedSymbol = interfaceDeclaration.GetFullyQualifiedIdentifier (); + Attributes = interfaceDeclaration.GetAttributeCodeChanges (context.SemanticModel); + UsingDirectives = interfaceDeclaration.SyntaxTree.CollectUsingStatements (); + Modifiers = [.. interfaceDeclaration.Modifiers]; + // we do not init the constructors, we use the default empty array + + GetMembers (interfaceDeclaration, context.SemanticModel, Skip, Property.TryCreate, + out properties); + GetMembers (interfaceDeclaration, context.SemanticModel, Skip, Event.TryCreate, + out events); + GetMembers (interfaceDeclaration, context.SemanticModel, Skip, Method.TryCreate, + out methods); + } + + /// + /// Create a CodeChange from the provide base type declaration syntax. If the syntax is not supported, + /// it will return null. + /// + /// The declaration syntax whose change we want to calculate. + /// The root binding context of the current compilation. + /// A code change or null if it could not be calculated. + public static CodeChanges? FromDeclaration (BaseTypeDeclarationSyntax baseTypeDeclarationSyntax, + RootBindingContext context) + => baseTypeDeclarationSyntax switch { + EnumDeclarationSyntax enumDeclarationSyntax => new CodeChanges (enumDeclarationSyntax, context), + InterfaceDeclarationSyntax interfaceDeclarationSyntax => new CodeChanges (interfaceDeclarationSyntax, + context), + ClassDeclarationSyntax classDeclarationSyntax => new CodeChanges (classDeclarationSyntax, context), + _ => null + }; +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.cs index c5a52c1fad2..a2e827c22db 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/CodeChanges.cs @@ -2,15 +2,12 @@ // Licensed under the MIT License. using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Macios.Generator.Availability; -using Microsoft.Macios.Generator.Context; -using Microsoft.Macios.Generator.Extensions; namespace Microsoft.Macios.Generator.DataModel; @@ -18,17 +15,8 @@ namespace Microsoft.Macios.Generator.DataModel; /// Structure that represents a set of changes that were made by the user that need to be applied to the /// generated code. /// -readonly struct CodeChanges { - /// - /// Represents the type of binding that the code changes are for. - /// - public BindingType BindingType => BindingInfo.BindingType; - - readonly BindingInfo bindingInfo = default; - /// - /// Represents the binding data that will be used to generate the code. - /// - public BindingInfo BindingInfo => bindingInfo; +[StructLayout (LayoutKind.Auto)] +readonly partial struct CodeChanges { readonly string name = string.Empty; /// @@ -167,264 +155,6 @@ public ImmutableArray Methods { init => methods = value; } - /// - /// Returns all the library names and paths that are needed by the native code represented by the code change. - /// - public IEnumerable<(string LibraryName, string? LibraryPath)> LibraryPaths { - get { - // we want to return unique values, A library name should always point to the - // same library path (either null or with a value). We keep track of the ones we already - // returned in a set and skip if we already returned it. - var visited = new HashSet (); - - // return those libs needed by smart enums - foreach (var enumMember in EnumMembers) { - if (enumMember.FieldInfo is null) - continue; - var (_, libraryName, libraryPath) = enumMember.FieldInfo.Value; - if (visited.Add (libraryName)) // if already visited, we cannot add it - yield return (libraryName, libraryPath); - } - - // return those libs needed by field properties - foreach (var property in Properties) { - if (property.ExportFieldData is null) - continue; - var (_, libraryName, libraryPath) = property.ExportFieldData.Value; - if (visited.Add (libraryName)) // if already visited, we cannot add it - yield return (libraryName, libraryPath); - } - } - } - - /// - /// Decide if an enum value should be ignored as a change. - /// - /// The enum declaration under test. - /// The semantic model of the compilation. - /// True if the enum value should be ignored. False otherwise. - internal static bool Skip (EnumMemberDeclarationSyntax enumMemberDeclarationSyntax, SemanticModel semanticModel) - { - // for smart enums, we are only interested in the field that has a Field attribute - return !enumMemberDeclarationSyntax.HasAttribute (semanticModel, AttributesNames.EnumFieldAttribute); - } - - /// - /// Decide if a property should be ignored as a change. - /// - /// The property declaration under test. - /// The semantic model of the compilation. - /// True if the property should be ignored. False otherwise. - internal static bool Skip (PropertyDeclarationSyntax propertyDeclarationSyntax, SemanticModel semanticModel) - { - // valid properties are: - // 1. Partial - // 2. One of the following: - // 1. Field properties - // 2. Exported properties - if (propertyDeclarationSyntax.Modifiers.Any (SyntaxKind.PartialKeyword)) { - return !propertyDeclarationSyntax.HasAtLeastOneAttribute (semanticModel, - AttributesNames.FieldPropertyAttribute, AttributesNames.ExportPropertyAttribute); - } - - return true; - } - - internal static bool Skip (ConstructorDeclarationSyntax constructorDeclarationSyntax, SemanticModel semanticModel) - { - // TODO: we need to confirm this when we have support from the roslyn team. - return false; - } - - internal static bool Skip (EventDeclarationSyntax eventDeclarationSyntax, SemanticModel semanticModel) - { - // TODO: we need to confirm this when we have support from the roslyn team. - return false; - } - - internal static bool Skip (MethodDeclarationSyntax methodDeclarationSyntax, SemanticModel semanticModel) - { - // Valid methods are: - // 1. Partial - // 2. Contain the export attribute - if (methodDeclarationSyntax.Modifiers.Any (SyntaxKind.PartialKeyword)) { - return !methodDeclarationSyntax.HasAttribute (semanticModel, AttributesNames.ExportMethodAttribute); - } - - return true; - } - - delegate bool SkipDelegate (T declarationSyntax, SemanticModel semanticModel); - - delegate bool TryCreateDelegate (T declaration, RootBindingContext context, - [NotNullWhen (true)] out TR? change) - where T : MemberDeclarationSyntax - where TR : struct; - - static void GetMembers (TypeDeclarationSyntax baseDeclarationSyntax, RootBindingContext context, - SkipDelegate skip, TryCreateDelegate tryCreate, out ImmutableArray members) - where T : MemberDeclarationSyntax - where TR : struct - { - var bucket = ImmutableArray.CreateBuilder (); - var declarations = baseDeclarationSyntax.Members.OfType (); - foreach (var declaration in declarations) { - if (skip (declaration, context.SemanticModel)) - continue; - if (tryCreate (declaration, context, out var change)) - bucket.Add (change.Value); - } - - members = bucket.ToImmutable (); - } - - /// - /// Internal constructor added for testing purposes. - /// - /// The binding data of binding for the given code changes. - /// The name of the named type that created the code change. - /// The namespace that contains the named type. - /// The fully qualified name of the symbol. - /// The platform availability of the named symbol. - internal CodeChanges (BindingInfo bindingInfo, string name, ImmutableArray @namespace, - string fullyQualifiedSymbol, SymbolAvailability symbolAvailability) - { - this.bindingInfo = bindingInfo; - this.name = name; - this.namespaces = @namespace; - FullyQualifiedSymbol = fullyQualifiedSymbol; - this.availability = symbolAvailability; - } - - /// - /// Creates a new instance of the struct for a given enum declaration. - /// - /// The enum declaration that triggered the change. - /// The root binding context of the current compilation. - CodeChanges (EnumDeclarationSyntax enumDeclaration, RootBindingContext context) - { - context.SemanticModel.GetSymbolData ( - declaration: enumDeclaration, - bindingType: BindingType.SmartEnum, - name: out name, - baseClass: out baseClass, - interfaces: out interfaces, - namespaces: out namespaces, - symbolAvailability: out availability, - bindingInfo: out bindingInfo); - FullyQualifiedSymbol = enumDeclaration.GetFullyQualifiedIdentifier (); - Attributes = enumDeclaration.GetAttributeCodeChanges (context.SemanticModel); - UsingDirectives = enumDeclaration.SyntaxTree.CollectUsingStatements (); - Modifiers = [.. enumDeclaration.Modifiers]; - var bucket = ImmutableArray.CreateBuilder (); - // loop over the fields and add those that contain a FieldAttribute - var enumValueDeclarations = enumDeclaration.Members.OfType (); - foreach (var enumValueDeclaration in enumValueDeclarations) { - if (Skip (enumValueDeclaration, context.SemanticModel)) - continue; - if (context.SemanticModel.GetDeclaredSymbol (enumValueDeclaration) is not IFieldSymbol enumValueSymbol) { - continue; - } - - var fieldData = enumValueSymbol.GetFieldData (); - // try and compute the library for this enum member - if (fieldData is null || !context.TryComputeLibraryName (fieldData.Value.LibraryName, Namespace [^1], - out string? libraryName, out string? libraryPath)) - // could not calculate the library for the enum, do not add it - continue; - var enumMember = new EnumMember ( - name: enumValueDeclaration.Identifier.ToFullString ().Trim (), - libraryName: libraryName, - libraryPath: libraryPath, - fieldData: enumValueSymbol.GetFieldData (), - symbolAvailability: enumValueSymbol.GetSupportedPlatforms (), - attributes: enumValueDeclaration.GetAttributeCodeChanges (context.SemanticModel) - ); - bucket.Add (enumMember); - } - - EnumMembers = bucket.ToImmutable (); - } - - /// - /// Creates a new instance of the struct for a given class declaration. - /// - /// The class declaration that triggered the change. - /// The root binding context of the current compilation. - CodeChanges (ClassDeclarationSyntax classDeclaration, RootBindingContext context) - { - context.SemanticModel.GetSymbolData ( - declaration: classDeclaration, - bindingType: BindingType.Class, - name: out name, - baseClass: out baseClass, - interfaces: out interfaces, - namespaces: out namespaces, - symbolAvailability: out availability, - bindingInfo: out bindingInfo); - FullyQualifiedSymbol = classDeclaration.GetFullyQualifiedIdentifier (); - Attributes = classDeclaration.GetAttributeCodeChanges (context.SemanticModel); - UsingDirectives = classDeclaration.SyntaxTree.CollectUsingStatements (); - Modifiers = [.. classDeclaration.Modifiers]; - - // use the generic method to get the members, we are using an out param to try an minimize the number of times - // the value types are copied - GetMembers (classDeclaration, context, Skip, - Constructor.TryCreate, out constructors); - GetMembers (classDeclaration, context, Skip, Property.TryCreate, - out properties); - GetMembers (classDeclaration, context, Skip, Event.TryCreate, out events); - GetMembers (classDeclaration, context, Skip, Method.TryCreate, - out methods); - } - - /// - /// Creates a new instance of the struct for a given interface declaration. - /// - /// The interface declaration that triggered the change. - /// The root binding context of the current compilation. - CodeChanges (InterfaceDeclarationSyntax interfaceDeclaration, RootBindingContext context) - { - context.SemanticModel.GetSymbolData ( - declaration: interfaceDeclaration, - bindingType: BindingType.Protocol, - name: out name, - baseClass: out baseClass, - interfaces: out interfaces, - namespaces: out namespaces, - symbolAvailability: out availability, - bindingInfo: out bindingInfo); - FullyQualifiedSymbol = interfaceDeclaration.GetFullyQualifiedIdentifier (); - Attributes = interfaceDeclaration.GetAttributeCodeChanges (context.SemanticModel); - UsingDirectives = interfaceDeclaration.SyntaxTree.CollectUsingStatements (); - Modifiers = [.. interfaceDeclaration.Modifiers]; - // we do not init the constructors, we use the default empty array - - GetMembers (interfaceDeclaration, context.SemanticModel, Skip, Property.TryCreate, - out properties); - GetMembers (interfaceDeclaration, context.SemanticModel, Skip, Event.TryCreate, - out events); - GetMembers (interfaceDeclaration, context.SemanticModel, Skip, Method.TryCreate, - out methods); - } - - /// - /// Create a CodeChange from the provide base type declaration syntax. If the syntax is not supported, - /// it will return null. - /// - /// The declaration syntax whose change we want to calculate. - /// The root binding context of the current compilation. - /// A code change or null if it could not be calculated. - public static CodeChanges? FromDeclaration (BaseTypeDeclarationSyntax baseTypeDeclarationSyntax, - RootBindingContext context) - => baseTypeDeclarationSyntax switch { - EnumDeclarationSyntax enumDeclarationSyntax => new CodeChanges (enumDeclarationSyntax, context), - InterfaceDeclarationSyntax interfaceDeclarationSyntax => new CodeChanges (interfaceDeclarationSyntax, - context), - ClassDeclarationSyntax classDeclarationSyntax => new CodeChanges (classDeclarationSyntax, context), - _ => null - }; - /// public override string ToString () { @@ -453,4 +183,5 @@ public override string ToString () sb.Append ("] }"); return sb.ToString (); } + } diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.Generator.cs new file mode 100644 index 00000000000..a3b14cce0c0 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.Generator.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Context; +using Microsoft.Macios.Generator.Extensions; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Constructor { + + public static bool TryCreate (ConstructorDeclarationSyntax declaration, RootBindingContext context, + [NotNullWhen (true)] out Constructor? change) + { + if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IMethodSymbol constructor) { + change = null; + return false; + } + + var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); + var parametersBucket = ImmutableArray.CreateBuilder (); + // loop over the parameters of the construct since changes on those implies a change in the generated code + foreach (var parameter in constructor.Parameters) { + var parameterDeclaration = declaration.ParameterList.Parameters [parameter.Ordinal]; + if (!Parameter.TryCreate (parameter, parameterDeclaration, context.SemanticModel, out var parameterChange)) + continue; + parametersBucket.Add (parameterChange.Value); + } + + change = new ( + type: constructor.ContainingSymbol.Name, // we DO NOT want the full name + symbolAvailability: constructor.GetSupportedPlatforms (), + attributes: attributes, + modifiers: [.. declaration.Modifiers], + parameters: parametersBucket.ToImmutable ()); + return true; + } +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.cs index 57e9f19cb5e..eee7d6a9104 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Constructor.cs @@ -2,18 +2,14 @@ // Licensed under the MIT License. using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Macios.Generator.Availability; -using Microsoft.Macios.Generator.Context; -using Microsoft.Macios.Generator.Extensions; namespace Microsoft.Macios.Generator.DataModel; -readonly struct Constructor : IEquatable { +readonly partial struct Constructor : IEquatable { /// /// Type name that owns the constructor. /// @@ -52,33 +48,6 @@ public Constructor (string type, Parameters = parameters; } - public static bool TryCreate (ConstructorDeclarationSyntax declaration, RootBindingContext context, - [NotNullWhen (true)] out Constructor? change) - { - if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IMethodSymbol constructor) { - change = null; - return false; - } - - var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); - var parametersBucket = ImmutableArray.CreateBuilder (); - // loop over the parameters of the construct since changes on those implies a change in the generated code - foreach (var parameter in constructor.Parameters) { - var parameterDeclaration = declaration.ParameterList.Parameters [parameter.Ordinal]; - if (!Parameter.TryCreate (parameter, parameterDeclaration, context.SemanticModel, out var parameterChange)) - continue; - parametersBucket.Add (parameterChange.Value); - } - - change = new ( - type: constructor.ContainingSymbol.Name, // we DO NOT want the full name - symbolAvailability: constructor.GetSupportedPlatforms (), - attributes: attributes, - modifiers: [.. declaration.Modifiers], - parameters: parametersBucket.ToImmutable ()); - return true; - } - /// public bool Equals (Constructor other) { diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.Generator.cs new file mode 100644 index 00000000000..252192f8b83 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.Generator.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.Macios.Generator.Attributes; +using Microsoft.Macios.Generator.Availability; +using ObjCBindings; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct EnumMember { + + /// + /// The data of the field attribute used to mark the value as a binding. + /// + public FieldInfo? FieldInfo { get; } + + /// + /// Create a new change that happened on a member. + /// + /// The name of the changed member. + /// The library name of the smart enum. + /// The library path to the library, null if it is a known frameworl. + /// The binding data attached to this enum value. + /// The symbol availability of the member. + /// The list of attribute changes in the member. + public EnumMember (string name, + string libraryName, + string? libraryPath, + FieldData? fieldData, + SymbolAvailability symbolAvailability, + ImmutableArray attributes) + { + Name = name; + FieldInfo = fieldData is null ? null : new (fieldData.Value, libraryName, libraryPath); + SymbolAvailability = symbolAvailability; + Attributes = attributes; + } + +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.cs index 003ac01b4a9..783650fa187 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/EnumMember.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. using System; using System.Collections.Immutable; +using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.Availability; @@ -13,7 +15,8 @@ namespace Microsoft.Macios.Generator.DataModel; /// Structure that represents a change that was made by the user on enum members that has to be /// reflected in the generated code. /// -readonly struct EnumMember : IEquatable { +[StructLayout (LayoutKind.Auto)] +readonly partial struct EnumMember : IEquatable { /// /// Get the name of the member. /// @@ -24,38 +27,11 @@ namespace Microsoft.Macios.Generator.DataModel; /// public SymbolAvailability SymbolAvailability { get; } - /// - /// The data of the field attribute used to mark the value as a binding. - /// - public FieldInfo? FieldInfo { get; } - /// /// Get the attributes added to the member. /// public ImmutableArray Attributes { get; } - /// - /// Create a new change that happened on a member. - /// - /// The name of the changed member. - /// The library name of the smart enum. - /// The library path to the library, null if it is a known frameworl. - /// The binding data attached to this enum value. - /// The symbol availability of the member. - /// The list of attribute changes in the member. - public EnumMember (string name, - string libraryName, - string? libraryPath, - FieldData? fieldData, - SymbolAvailability symbolAvailability, - ImmutableArray attributes) - { - Name = name; - FieldInfo = fieldData is null ? null : new (fieldData.Value, libraryName, libraryPath); - SymbolAvailability = symbolAvailability; - Attributes = attributes; - } - /// /// Create a new change that happened on a member. /// diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Event.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Event.Generator.cs new file mode 100644 index 00000000000..ebbcd469e0d --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Event.Generator.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Context; +using Microsoft.Macios.Generator.Extensions; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Event { + + public static bool TryCreate (EventDeclarationSyntax declaration, RootBindingContext context, + [NotNullWhen (true)] out Event? change) + { + var memberName = declaration.Identifier.ToFullString ().Trim (); + // get the symbol from the property declaration + if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IEventSymbol eventSymbol) { + change = null; + return false; + } + + var type = eventSymbol.Type.ToDisplayString ().Trim (); + var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); + ImmutableArray accessorCodeChanges = []; + if (declaration.AccessorList is not null && declaration.AccessorList.Accessors.Count > 0) { + // calculate any possible changes in the accessors of the property + var accessorsBucket = ImmutableArray.CreateBuilder (); + foreach (var accessorDeclaration in declaration.AccessorList.Accessors) { + if (context.SemanticModel.GetDeclaredSymbol (accessorDeclaration) is not ISymbol accessorSymbol) + continue; + var kind = accessorDeclaration.Kind ().ToAccessorKind (); + var accessorAttributeChanges = accessorDeclaration.GetAttributeCodeChanges (context.SemanticModel); + accessorsBucket.Add (new ( + accessorKind: kind, + symbolAvailability: accessorSymbol.GetSupportedPlatforms (), + exportPropertyData: null, + attributes: accessorAttributeChanges, + modifiers: [.. accessorDeclaration.Modifiers])); + } + + accessorCodeChanges = accessorsBucket.ToImmutable (); + } + + change = new (memberName, type, eventSymbol.GetSupportedPlatforms (), attributes, + [.. declaration.Modifiers], accessorCodeChanges); + return true; + } +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Event.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Event.cs index 38f7e5e10b8..3b53660c7a3 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/Event.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Event.cs @@ -2,18 +2,14 @@ // Licensed under the MIT License. using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Macios.Generator.Availability; -using Microsoft.Macios.Generator.Context; -using Microsoft.Macios.Generator.Extensions; namespace Microsoft.Macios.Generator.DataModel; -readonly struct Event : IEquatable { +readonly partial struct Event : IEquatable { /// /// Name of the property. /// @@ -101,43 +97,6 @@ public override int GetHashCode () return !left.Equals (right); } - public static bool TryCreate (EventDeclarationSyntax declaration, RootBindingContext context, - [NotNullWhen (true)] out Event? change) - { - var memberName = declaration.Identifier.ToFullString ().Trim (); - // get the symbol from the property declaration - if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IEventSymbol eventSymbol) { - change = null; - return false; - } - - var type = eventSymbol.Type.ToDisplayString ().Trim (); - var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); - ImmutableArray accessorCodeChanges = []; - if (declaration.AccessorList is not null && declaration.AccessorList.Accessors.Count > 0) { - // calculate any possible changes in the accessors of the property - var accessorsBucket = ImmutableArray.CreateBuilder (); - foreach (var accessorDeclaration in declaration.AccessorList.Accessors) { - if (context.SemanticModel.GetDeclaredSymbol (accessorDeclaration) is not ISymbol accessorSymbol) - continue; - var kind = accessorDeclaration.Kind ().ToAccessorKind (); - var accessorAttributeChanges = accessorDeclaration.GetAttributeCodeChanges (context.SemanticModel); - accessorsBucket.Add (new ( - accessorKind: kind, - symbolAvailability: accessorSymbol.GetSupportedPlatforms (), - exportPropertyData: null, - attributes: accessorAttributeChanges, - modifiers: [.. accessorDeclaration.Modifiers])); - } - - accessorCodeChanges = accessorsBucket.ToImmutable (); - } - - change = new (memberName, type, eventSymbol.GetSupportedPlatforms (), attributes, - [.. declaration.Modifiers], accessorCodeChanges); - return true; - } - /// public override string ToString () { diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Method.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Method.Generator.cs new file mode 100644 index 00000000000..fefb41c4f79 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Method.Generator.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Attributes; +using Microsoft.Macios.Generator.Availability; +using Microsoft.Macios.Generator.Context; +using Microsoft.Macios.Generator.Extensions; +using ObjCRuntime; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Method { + + /// + /// The data of the export attribute used to mark the value as a property binding. + /// + public ExportData ExportMethodData { get; } + + /// + /// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions. + /// + public bool MarshalNativeExceptions => ExportMethodData.Flags.HasFlag (ObjCBindings.Method.MarshalNativeExceptions); + + public Method (string type, string name, TypeInfo returnType, + SymbolAvailability symbolAvailability, + ExportData exportMethodData, + ImmutableArray attributes, + ImmutableArray modifiers, + ImmutableArray parameters) + { + Type = type; + Name = name; + ReturnType = returnType; + SymbolAvailability = symbolAvailability; + ExportMethodData = exportMethodData; + Attributes = attributes; + Modifiers = modifiers; + Parameters = parameters; + } + + public static bool TryCreate (MethodDeclarationSyntax declaration, RootBindingContext context, + [NotNullWhen (true)] out Method? change) + { + if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IMethodSymbol method) { + change = null; + return false; + } + + var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); + var parametersBucket = ImmutableArray.CreateBuilder (); + // loop over the parameters of the construct since changes on those implies a change in the generated code + foreach (var parameter in method.Parameters) { + var parameterDeclaration = declaration.ParameterList.Parameters [parameter.Ordinal]; + if (!Parameter.TryCreate (parameter, parameterDeclaration, context.SemanticModel, out var parameterChange)) + continue; + parametersBucket.Add (parameterChange.Value); + } + + // DO NOT USE default if null, the reason is that it will set the ArgumentSemantics to be value 0, when + // none is value 1. The reason for that is that the default of an enum is 0, that was a mistake + // in the old binding code. + var exportData = method.GetExportData () + ?? new (null, ArgumentSemantic.None, ObjCBindings.Method.Default); + + change = new ( + type: method.ContainingSymbol.ToDisplayString ().Trim (), // we want the full name + name: method.Name, + returnType: new TypeInfo (method.ReturnType), + symbolAvailability: method.GetSupportedPlatforms (), + exportMethodData: exportData, + attributes: attributes, + modifiers: [.. declaration.Modifiers], + parameters: parametersBucket.ToImmutableArray ()); + + return true; + } +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs index 476d9f2b53c..4be3968ba03 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Method.cs @@ -2,20 +2,16 @@ // Licensed under the MIT License. using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.Availability; -using Microsoft.Macios.Generator.Context; -using Microsoft.Macios.Generator.Extensions; -using ObjCRuntime; namespace Microsoft.Macios.Generator.DataModel; -readonly struct Method : IEquatable { +[StructLayout (LayoutKind.Auto)] +readonly partial struct Method : IEquatable { /// /// Type name that owns the method. @@ -37,16 +33,6 @@ namespace Microsoft.Macios.Generator.DataModel; /// public SymbolAvailability SymbolAvailability { get; } - /// - /// The data of the export attribute used to mark the value as a property binding. - /// - public ExportData ExportMethodData { get; } - - /// - /// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions. - /// - public bool MarshalNativeExceptions => ExportMethodData.Flags.HasFlag (ObjCBindings.Method.MarshalNativeExceptions); - /// /// Get the attributes added to the constructor. /// @@ -62,58 +48,6 @@ namespace Microsoft.Macios.Generator.DataModel; /// public ImmutableArray Parameters { get; } = []; - public Method (string type, string name, TypeInfo returnType, - SymbolAvailability symbolAvailability, - ExportData exportMethodData, - ImmutableArray attributes, - ImmutableArray modifiers, - ImmutableArray parameters) - { - Type = type; - Name = name; - ReturnType = returnType; - SymbolAvailability = symbolAvailability; - ExportMethodData = exportMethodData; - Attributes = attributes; - Modifiers = modifiers; - Parameters = parameters; - } - - public static bool TryCreate (MethodDeclarationSyntax declaration, RootBindingContext context, - [NotNullWhen (true)] out Method? change) - { - if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IMethodSymbol method) { - change = null; - return false; - } - - var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); - var parametersBucket = ImmutableArray.CreateBuilder (); - // loop over the parameters of the construct since changes on those implies a change in the generated code - foreach (var parameter in method.Parameters) { - var parameterDeclaration = declaration.ParameterList.Parameters [parameter.Ordinal]; - if (!Parameter.TryCreate (parameter, parameterDeclaration, context.SemanticModel, out var parameterChange)) - continue; - parametersBucket.Add (parameterChange.Value); - } - - // DO NOT USE default if null, the reason is that it will set the ArgumentSemantics to be value 0, when - // none is value 1. The reason for that is that the default of an enum is 0, that was a mistake - // in the old binding code. - var exportData = method.GetExportData () - ?? new (null, ArgumentSemantic.None, ObjCBindings.Method.Default); - change = new ( - type: method.ContainingSymbol.ToDisplayString ().Trim (), // we want the full name - name: method.Name, - returnType: new (method.ReturnType), - symbolAvailability: method.GetSupportedPlatforms (), - exportMethodData: exportData, - attributes: attributes, - modifiers: [.. declaration.Modifiers], - parameters: parametersBucket.ToImmutableArray ()); - return true; - } - /// public bool Equals (Method other) { diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs new file mode 100644 index 00000000000..0320eb67da3 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Macios.Generator.Attributes; +using Microsoft.Macios.Generator.Context; +using Microsoft.Macios.Generator.Extensions; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Property { + + /// + /// The data of the field attribute used to mark the value as a field binding. + /// + public FieldInfo? ExportFieldData { get; init; } + + /// + /// True if the property represents a Objc field. + /// + [MemberNotNullWhen (true, nameof (ExportFieldData))] + public bool IsField => ExportFieldData is not null; + + public bool IsNotification + => IsField && ExportFieldData.Value.FieldData.Flags.HasFlag (ObjCBindings.Property.Notification); + + /// + /// The data of the field attribute used to mark the value as a property binding. + /// + public ExportData? ExportPropertyData { get; init; } + + /// + /// True if the property represents a Objc property. + /// + [MemberNotNullWhen (true, nameof (ExportPropertyData))] + public bool IsProperty => ExportPropertyData is not null; + + /// + /// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions. + /// + public bool MarshalNativeExceptions + => IsProperty && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions); + + static FieldInfo? GetFieldInfo (RootBindingContext context, IPropertySymbol propertySymbol) + { + // grab the last port of the namespace + var ns = propertySymbol.ContainingNamespace.Name.Split ('.') [^1]; + var fieldData = propertySymbol.GetFieldData (); + FieldInfo? fieldInfo = null; + if (fieldData is not null && context.TryComputeLibraryName (fieldData.Value.LibraryName, ns, + out string? libraryName, out string? libraryPath)) { + fieldInfo = new FieldInfo (fieldData.Value, libraryName, libraryPath); + } + + return fieldInfo; + } + + public static bool TryCreate (PropertyDeclarationSyntax declaration, RootBindingContext context, + [NotNullWhen (true)] out Property? change) + { + var memberName = declaration.Identifier.ToFullString ().Trim (); + // get the symbol from the property declaration + if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IPropertySymbol propertySymbol) { + change = null; + return false; + } + + var propertySupportedPlatforms = propertySymbol.GetSupportedPlatforms (); + var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); + + ImmutableArray accessorCodeChanges = []; + if (declaration.AccessorList is not null && declaration.AccessorList.Accessors.Count > 0) { + // calculate any possible changes in the accessors of the property + var accessorsBucket = ImmutableArray.CreateBuilder (); + foreach (var accessorDeclaration in declaration.AccessorList.Accessors) { + if (context.SemanticModel.GetDeclaredSymbol (accessorDeclaration) is not ISymbol accessorSymbol) + continue; + var kind = accessorDeclaration.Kind ().ToAccessorKind (); + var accessorAttributeChanges = + accessorDeclaration.GetAttributeCodeChanges (context.SemanticModel); + accessorsBucket.Add (new ( + accessorKind: kind, + exportPropertyData: accessorSymbol.GetExportData (), + symbolAvailability: accessorSymbol.GetSupportedPlatforms (), + attributes: accessorAttributeChanges, + modifiers: [.. accessorDeclaration.Modifiers])); + } + + accessorCodeChanges = accessorsBucket.ToImmutable (); + } + + if (declaration.ExpressionBody is not null) { + // an expression body == a getter with no attrs or modifiers; that means that the accessor does not have + // extra availability, but the ones form the property + accessorCodeChanges = [new ( + accessorKind: AccessorKind.Getter, + symbolAvailability: propertySupportedPlatforms, + exportPropertyData: null, + attributes: [], + modifiers: []) + ]; + } + + change = new ( + name: memberName, + returnType: new (propertySymbol.Type), + symbolAvailability: propertySupportedPlatforms, + attributes: attributes, + modifiers: [.. declaration.Modifiers], + accessors: accessorCodeChanges) { + ExportFieldData = GetFieldInfo (context, propertySymbol), + ExportPropertyData = propertySymbol.GetExportData (), + }; + return true; + } +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs index bc1f4d1e45a..cef7185bf36 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/Property.cs @@ -2,22 +2,19 @@ // Licensed under the MIT License. using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.Macios.Generator.Attributes; using Microsoft.Macios.Generator.Availability; -using Microsoft.Macios.Generator.Context; -using Microsoft.Macios.Generator.Extensions; namespace Microsoft.Macios.Generator.DataModel; /// /// Readonly struct that represent the changes that a user has made in a property. /// -readonly struct Property : IEquatable { +[StructLayout (LayoutKind.Auto)] +readonly partial struct Property : IEquatable { /// /// Name of the property. /// @@ -50,42 +47,11 @@ namespace Microsoft.Macios.Generator.DataModel; /// public SymbolAvailability SymbolAvailability { get; } - /// - /// The data of the field attribute used to mark the value as a field binding. - /// - public FieldInfo? ExportFieldData { get; init; } - - /// - /// True if the property represents a Objc field. - /// - [MemberNotNullWhen (true, nameof (ExportFieldData))] - public bool IsField => ExportFieldData is not null; - - public bool IsNotification - => IsField && ExportFieldData.Value.FieldData.Flags.HasFlag (ObjCBindings.Property.Notification); - - /// - /// The data of the field attribute used to mark the value as a property binding. - /// - public ExportData? ExportPropertyData { get; init; } - - /// - /// True if the property represents a Objc property. - /// - [MemberNotNullWhen (true, nameof (ExportPropertyData))] - public bool IsProperty => ExportPropertyData is not null; - /// /// Get the attributes added to the member. /// public ImmutableArray Attributes { get; } = []; - /// - /// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions. - /// - public bool MarshalNativeExceptions - => IsProperty && ExportPropertyData.Value.Flags.HasFlag (ObjCBindings.Property.MarshalNativeExceptions); - /// /// Get the modifiers of the property. /// @@ -175,79 +141,6 @@ public override int GetHashCode () return !left.Equals (right); } - static FieldInfo? GetFieldInfo (RootBindingContext context, IPropertySymbol propertySymbol) - { - // grab the last port of the namespace - var ns = propertySymbol.ContainingNamespace.Name.Split ('.') [^1]; - var fieldData = propertySymbol.GetFieldData (); - FieldInfo? fieldInfo = null; - if (fieldData is not null && context.TryComputeLibraryName (fieldData.Value.LibraryName, ns, - out string? libraryName, out string? libraryPath)) { - fieldInfo = new FieldInfo (fieldData.Value, libraryName, libraryPath); - } - - return fieldInfo; - } - - public static bool TryCreate (PropertyDeclarationSyntax declaration, RootBindingContext context, - [NotNullWhen (true)] out Property? change) - { - var memberName = declaration.Identifier.ToFullString ().Trim (); - // get the symbol from the property declaration - if (context.SemanticModel.GetDeclaredSymbol (declaration) is not IPropertySymbol propertySymbol) { - change = null; - return false; - } - - var propertySupportedPlatforms = propertySymbol.GetSupportedPlatforms (); - var attributes = declaration.GetAttributeCodeChanges (context.SemanticModel); - - ImmutableArray accessorCodeChanges = []; - if (declaration.AccessorList is not null && declaration.AccessorList.Accessors.Count > 0) { - // calculate any possible changes in the accessors of the property - var accessorsBucket = ImmutableArray.CreateBuilder (); - foreach (var accessorDeclaration in declaration.AccessorList.Accessors) { - if (context.SemanticModel.GetDeclaredSymbol (accessorDeclaration) is not ISymbol accessorSymbol) - continue; - var kind = accessorDeclaration.Kind ().ToAccessorKind (); - var accessorAttributeChanges = - accessorDeclaration.GetAttributeCodeChanges (context.SemanticModel); - accessorsBucket.Add (new ( - accessorKind: kind, - exportPropertyData: accessorSymbol.GetExportData (), - symbolAvailability: accessorSymbol.GetSupportedPlatforms (), - attributes: accessorAttributeChanges, - modifiers: [.. accessorDeclaration.Modifiers])); - } - - accessorCodeChanges = accessorsBucket.ToImmutable (); - } - - if (declaration.ExpressionBody is not null) { - // an expression body == a getter with no attrs or modifiers; that means that the accessor does not have - // extra availability, but the ones form the property - accessorCodeChanges = [new ( - accessorKind: AccessorKind.Getter, - symbolAvailability: propertySupportedPlatforms, - exportPropertyData: null, - attributes: [], - modifiers: []) - ]; - } - - change = new ( - name: memberName, - returnType: new (propertySymbol.Type), - symbolAvailability: propertySupportedPlatforms, - attributes: attributes, - modifiers: [.. declaration.Modifiers], - accessors: accessorCodeChanges) { - ExportFieldData = GetFieldInfo (context, propertySymbol), - ExportPropertyData = propertySymbol.GetExportData (), - }; - return true; - } - /// public override string ToString () { diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs new file mode 100644 index 00000000000..2c2d4984ca0 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.Generator.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis; +using Microsoft.Macios.Generator.Extensions; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct TypeInfo { + + internal TypeInfo (ITypeSymbol symbol) : + this ( + symbol is IArrayTypeSymbol arrayTypeSymbol + ? arrayTypeSymbol.ElementType.ToDisplayString () + : symbol.ToDisplayString ().Trim ('?', '[', ']'), + symbol.SpecialType) + { + IsNullable = symbol.NullableAnnotation == NullableAnnotation.Annotated; + IsBlittable = symbol.IsBlittable (); + IsSmartEnum = symbol.IsSmartEnum (); + IsArray = symbol is IArrayTypeSymbol; + IsReferenceType = symbol.IsReferenceType; + IsInterface = symbol.TypeKind == TypeKind.Interface; + IsNativeIntegerType = symbol.IsNativeIntegerType; + IsNativeEnum = symbol.HasAttribute (AttributesNames.NativeEnumAttribute); + + // data that we can get from the symbol without being INamedType + symbol.GetInheritance ( + isNSObject: out isNSObject, + isNativeObject: out isINativeObject, + parents: out parents, + interfaces: out interfaces); + + // try to get the named type symbol to have more educated decisions + var namedTypeSymbol = symbol as INamedTypeSymbol; + + // store the enum special type, useful when generate code that needs to cast + EnumUnderlyingType = namedTypeSymbol?.EnumUnderlyingType?.SpecialType; + + if (!IsReferenceType && IsNullable && namedTypeSymbol is not null) { + // get the type argument for nullable, which we know is the data that was boxed and use it to + // overwrite the SpecialType + var typeArgument = namedTypeSymbol.TypeArguments [0]; + SpecialType = typeArgument.SpecialType; + MetadataName = SpecialType is SpecialType.None or SpecialType.System_Void + ? null : typeArgument.MetadataName; + } else { + MetadataName = SpecialType is SpecialType.None or SpecialType.System_Void + ? null : symbol.MetadataName; + } + + } + +} diff --git a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs index ae4d1a23d05..6377c09451e 100644 --- a/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs +++ b/src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs @@ -5,14 +5,13 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.Macios.Generator.Extensions; namespace Microsoft.Macios.Generator.DataModel; /// /// Readonly structure that represents a change in a method return type. /// -readonly struct TypeInfo : IEquatable { +readonly partial struct TypeInfo : IEquatable { /// /// Type of the parameter. @@ -136,49 +135,6 @@ internal TypeInfo (string name, IsReferenceType = isReferenceType; } - internal TypeInfo (ITypeSymbol symbol) : - this ( - symbol is IArrayTypeSymbol arrayTypeSymbol - ? arrayTypeSymbol.ElementType.ToDisplayString () - : symbol.ToDisplayString ().Trim ('?', '[', ']'), - symbol.SpecialType) - { - IsNullable = symbol.NullableAnnotation == NullableAnnotation.Annotated; - IsBlittable = symbol.IsBlittable (); - IsSmartEnum = symbol.IsSmartEnum (); - IsArray = symbol is IArrayTypeSymbol; - IsReferenceType = symbol.IsReferenceType; - IsInterface = symbol.TypeKind == TypeKind.Interface; - IsNativeIntegerType = symbol.IsNativeIntegerType; - IsNativeEnum = symbol.HasAttribute (AttributesNames.NativeEnumAttribute); - - // data that we can get from the symbol without being INamedType - symbol.GetInheritance ( - isNSObject: out isNSObject, - isNativeObject: out isINativeObject, - parents: out parents, - interfaces: out interfaces); - - // try to get the named type symbol to have more educated decisions - var namedTypeSymbol = symbol as INamedTypeSymbol; - - // store the enum special type, useful when generate code that needs to cast - EnumUnderlyingType = namedTypeSymbol?.EnumUnderlyingType?.SpecialType; - - if (!IsReferenceType && IsNullable && namedTypeSymbol is not null) { - // get the type argument for nullable, which we know is the data that was boxed and use it to - // overwrite the SpecialType - var typeArgument = namedTypeSymbol.TypeArguments [0]; - SpecialType = typeArgument.SpecialType; - MetadataName = SpecialType is SpecialType.None or SpecialType.System_Void - ? null : typeArgument.MetadataName; - } else { - MetadataName = SpecialType is SpecialType.None or SpecialType.System_Void - ? null : symbol.MetadataName; - } - - } - /// public bool Equals (TypeInfo other) { diff --git a/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs b/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs new file mode 100644 index 00000000000..264ac1ce961 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Attributes/ExportData.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Macios.Transformer.Attributes; + +public struct ExportData : IEquatable { + + public bool Equals (ExportData other) + { + throw new NotImplementedException (); + } + + /// + public override bool Equals (object? obj) + { + return obj is ExportData other && Equals (other); + } + + /// + public override int GetHashCode () + { + throw new NotImplementedException (); + } + + public static bool operator == (ExportData x, ExportData y) + { + return x.Equals (y); + } + + public static bool operator != (ExportData x, ExportData y) + { + return !(x == y); + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs b/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs new file mode 100644 index 00000000000..3f7c0e824d8 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Attributes/FieldData.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Macios.Transformer.Attributes; + +public struct FieldData : IEquatable { + + public bool Equals (FieldData other) + { + throw new NotImplementedException (); + } + + /// + public override bool Equals (object? obj) + { + return obj is ExportData other && Equals (other); + } + + /// + public override int GetHashCode () + { + throw new NotImplementedException (); + } + + public static bool operator == (FieldData x, FieldData y) + { + return x.Equals (y); + } + + public static bool operator != (FieldData x, FieldData y) + { + return !(x == y); + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/Accessor.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/Accessor.Transformer.cs new file mode 100644 index 00000000000..3220114a142 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/Accessor.Transformer.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Macios.Transformer.Attributes; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Accessor { + + public ExportData? ExportPropertyData { get; init; } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/BindingInfo.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/BindingInfo.cs new file mode 100644 index 00000000000..049e67c427e --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/BindingInfo.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Macios.Generator.DataModel; + +/// +/// This struct works as a union to store the possible BindingTypeData that can be present in the bindings. +/// +readonly struct BindingInfo : IEquatable { + + /// + public bool Equals (BindingInfo other) + { + throw new NotImplementedException (); + } + + /// + public override bool Equals (object? obj) + { + return obj is BindingInfo other && Equals (other); + } + + /// + public override int GetHashCode () + { + throw new NotImplementedException (); + } + + public static bool operator == (BindingInfo x, BindingInfo y) + { + return x.Equals (y); + } + + public static bool operator != (BindingInfo x, BindingInfo y) + { + return !(x == y); + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/CodeChanges.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/CodeChanges.Transformer.cs new file mode 100644 index 00000000000..703f48f9eb4 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/CodeChanges.Transformer.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct CodeChanges { + + /// + /// Represents the type of binding that the code changes are for. + /// + public BindingType BindingType => throw new NotImplementedException (); + + public BindingInfo BindingInfo => throw new NotImplementedException (); + + public CodeChanges () + { + FullyQualifiedSymbol = ""; + IsStatic = false; + IsPartial = false; + IsAbstract = false; + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/EnumMember.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/EnumMember.Transformer.cs new file mode 100644 index 00000000000..6f5548abc72 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/EnumMember.Transformer.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.Macios.Generator.Availability; +using Microsoft.Macios.Transformer.Attributes; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct EnumMember { + + /// + /// The data of the field attribute used to mark the value as a binding. + /// + public FieldData? FieldInfo { get; } + + /// + /// Create a new change that happened on a member. + /// + /// The name of the changed member. + /// The library name of the smart enum. + /// The library path to the library, null if it is a known frameworl. + /// The binding data attached to this enum value. + /// The symbol availability of the member. + /// The list of attribute changes in the member. + public EnumMember (string name, + string libraryName, + string? libraryPath, + FieldData? fieldData, + SymbolAvailability symbolAvailability, + ImmutableArray attributes) + { + throw new NotImplementedException (); + } + +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/Method.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/Method.Transformer.cs new file mode 100644 index 00000000000..fd2db969254 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/Method.Transformer.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.Macios.Generator.Availability; +using Microsoft.Macios.Transformer.Attributes; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Method { + + /// + /// The data of the export attribute used to mark the value as a property binding. + /// + public ExportData ExportMethodData { get; } + + /// + /// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions. + /// + public bool MarshalNativeExceptions => throw new NotImplementedException (); + + public Method (string type, string name, TypeInfo returnType, + SymbolAvailability symbolAvailability, + ExportData exportMethodData, + ImmutableArray attributes, + ImmutableArray modifiers, + ImmutableArray parameters) + { + Type = type; + Name = name; + ReturnType = returnType; + SymbolAvailability = symbolAvailability; + ExportMethodData = exportMethodData; + Attributes = attributes; + Modifiers = modifiers; + Parameters = parameters; + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/Property.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/Property.Transformer.cs new file mode 100644 index 00000000000..682ca922622 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/Property.Transformer.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; +using Microsoft.Macios.Transformer.Attributes; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct Property { + + /// + /// The data of the field attribute used to mark the value as a field binding. + /// + public FieldData? ExportFieldData { get; init; } + + /// + /// True if the property represents a Objc field. + /// + [MemberNotNullWhen (true, nameof (ExportFieldData))] + public bool IsField => ExportFieldData is not null; + + public bool IsNotification => throw new NotImplementedException (); + + /// + /// The data of the field attribute used to mark the value as a property binding. + /// + public ExportData? ExportPropertyData { get; init; } + + /// + /// True if the property represents a Objc property. + /// + [MemberNotNullWhen (true, nameof (ExportPropertyData))] + public bool IsProperty => ExportPropertyData is not null; + + /// + /// True if the method was exported with the MarshalNativeExceptions flag allowing it to support native exceptions. + /// + public bool MarshalNativeExceptions => throw new NotImplementedException (); +} diff --git a/src/rgen/Microsoft.Macios.Transformer/DataModel/TypeInfo.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/DataModel/TypeInfo.Transformer.cs new file mode 100644 index 00000000000..a0d4ea7ef22 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/DataModel/TypeInfo.Transformer.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis; + +namespace Microsoft.Macios.Generator.DataModel; + +readonly partial struct TypeInfo { + + internal TypeInfo (ITypeSymbol symbol) : + this ( + symbol is IArrayTypeSymbol arrayTypeSymbol + ? arrayTypeSymbol.ElementType.ToDisplayString () + : symbol.ToDisplayString ().Trim ('?', '[', ']'), + symbol.SpecialType) + { + throw new NotImplementedException (); + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs b/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs new file mode 100644 index 00000000000..0b1b6a70cb9 --- /dev/null +++ b/src/rgen/Microsoft.Macios.Transformer/Extensions/TypeSymbolExtensions.Transformer.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.CodeAnalysis; + +namespace Microsoft.Macios.Generator.Extensions; + +static partial class TypeSymbolExtensions { + + public static bool IsSmartEnum (this ITypeSymbol symbol) + { + throw new NotImplementedException (); + } +} diff --git a/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj b/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj index 3d0ac820d62..e86488747c8 100644 --- a/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj +++ b/src/rgen/Microsoft.Macios.Transformer/Microsoft.Macios.Transformer.csproj @@ -25,6 +25,9 @@ DictionaryComparer.cs + + CollectionComparer.cs + Attributes/ObsoletedOSPlatformData.cs @@ -37,6 +40,9 @@ Availability/*.cs + + Extensions/ParameterSyntaxExtensions.cs + Extensions/StringExtensions.cs @@ -45,6 +51,19 @@ + + + DataModel/*.cs + + + + + + + + + +