Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rgen] Implement the filtering in the transformer tool. #22012

Merged
merged 3 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
<Compile Include="../Microsoft.Macios.Generator/Extensions/CompilationExtensions.cs" >
<Link>Generator/Extensions/CompilationExtensions.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.cs" >
<Link>Generator/Extensions/TypeSymbolExtensions.cs</Link>
<Compile Include="../Microsoft.Macios.Generator/Extensions/TypeSymbolExtensions.Core.cs">
<Link>Generator/Extensions/TypeSymbolExtensions.Core.cs</Link>
</Compile>
<Compile Include="../Microsoft.Macios.Generator/Extensions/TypedConstantExtensions.cs" >
<Link>Generator/Extensions/TypedConstantExtensions.cs</Link>
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
/// <summary>
/// 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.
Expand Down Expand Up @@ -71,74 +68,6 @@ public static ImmutableArray<ISymbol> GetParents (this ISymbol symbol)
return [.. result];
}

/// <summary>
/// Return the symbol availability WITHOUT taking into account the parent symbols availability.
/// </summary>
/// <param name="symbol">The symbols whose availability attributes we want to retrieve.</param>
/// <returns>The symbol availability WITHOUT taking into account the parent symbols.</returns>
/// <remarks>This is a helper method, you probably don't want to use it.</remarks>
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 ();
}

/// <summary>
/// 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.
/// </summary>
/// <param name="symbol">The symbol whose availability we want to retrieve.</param>
/// <returns>A symbol availability structure for the symbol.</returns>
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 ();
Expand All @@ -156,56 +85,6 @@ 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<T> GetBindingData<T> (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<T> ();
foreach (var attributeData in boundAttributes) {
var attrName = attributeData.AttributeClass?.ToDisplayString ();
if (string.IsNullOrEmpty (attrName) || attrName != targetAttrName)
continue;
if (BindingTypeData<T>.TryParse (attributeData, out var bindingData)) {
return bindingData.Value;
}
}

return default;
}

delegate string? GetAttributeNames ();

delegate bool TryParse<T> (AttributeData data, [NotNullWhen (true)] out T? value) where T : struct;
Expand Down Expand Up @@ -235,28 +114,6 @@ public static BindingTypeData<T> GetBindingData<T> (this ISymbol symbol) where T
return null;
}

/// <summary>
/// Retrieve the data of an export attribute on a symbol.
/// </summary>
/// <param name="symbol">The tagged symbol.</param>
/// <typeparam name="T">Enum type used in the attribute.</typeparam>
/// <returns>The data of the export attribute if present or null if it was not found.</returns>
/// <remarks>If the passed enum is unknown or not supported as an enum for the export attribute, null will be
/// returned.</remarks>
public static ExportData<T>? GetExportData<T> (this ISymbol symbol) where T : Enum
=> GetAttribute<ExportData<T>> (symbol, AttributesNames.GetExportAttributeName<T>, ExportData<T>.TryParse);

/// <summary>
/// Retrieve the data of a field attribute on a symbol.
/// </summary>
/// <param name="symbol">The tagged symbol.</param>
/// <typeparam name="T">Enum type used in the attribute.</typeparam>
/// <returns>The data of the export attribute if present or null if it was not found.</returns>
/// <remarks>If the passed enum is unknown or not supported as an enum for the field attribute, null will be
/// returned.</remarks>
public static FieldData<T>? GetFieldData<T> (this ISymbol symbol) where T : Enum
=> GetAttribute<FieldData<T>> (symbol, AttributesNames.GetFieldAttributeName<T>, FieldData<T>.TryParse);

/// <summary>
/// Returns if a type is blittable or not.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {

/// <summary>
/// Return the symbol availability WITHOUT taking into account the parent symbols availability.
/// </summary>
/// <param name="symbol">The symbols whose availability attributes we want to retrieve.</param>
/// <returns>The symbol availability WITHOUT taking into account the parent symbols.</returns>
/// <remarks>This is a helper method, you probably don't want to use it.</remarks>
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 ();
}

/// <summary>
/// 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.
/// </summary>
/// <param name="symbol">The symbol whose availability we want to retrieve.</param>
/// <returns>A symbol availability structure for the symbol.</returns>
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<T> GetBindingData<T> (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<T> ();
foreach (var attributeData in boundAttributes) {
var attrName = attributeData.AttributeClass?.ToDisplayString ();
if (string.IsNullOrEmpty (attrName) || attrName != targetAttrName)
continue;
if (BindingTypeData<T>.TryParse (attributeData, out var bindingData)) {
return bindingData.Value;
}
}

return default;
}

/// <summary>
/// Retrieve the data of an export attribute on a symbol.
/// </summary>
/// <param name="symbol">The tagged symbol.</param>
/// <typeparam name="T">Enum type used in the attribute.</typeparam>
/// <returns>The data of the export attribute if present or null if it was not found.</returns>
/// <remarks>If the passed enum is unknown or not supported as an enum for the export attribute, null will be
/// returned.</remarks>
public static ExportData<T>? GetExportData<T> (this ISymbol symbol) where T : Enum
=> GetAttribute<ExportData<T>> (symbol, AttributesNames.GetExportAttributeName<T>, ExportData<T>.TryParse);

/// <summary>
/// Retrieve the data of a field attribute on a symbol.
/// </summary>
/// <param name="symbol">The tagged symbol.</param>
/// <typeparam name="T">Enum type used in the attribute.</typeparam>
/// <returns>The data of the export attribute if present or null if it was not found.</returns>
/// <remarks>If the passed enum is unknown or not supported as an enum for the field attribute, null will be
/// returned.</remarks>
public static FieldData<T>? GetFieldData<T> (this ISymbol symbol) where T : Enum
=> GetAttribute<FieldData<T>> (symbol, AttributesNames.GetFieldAttributeName<T>, FieldData<T>.TryParse);
}
48 changes: 48 additions & 0 deletions src/rgen/Microsoft.Macios.Transformer/AttributesNames.cs
Original file line number Diff line number Diff line change
@@ -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";
}
Loading