-
Notifications
You must be signed in to change notification settings - Fork 730
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(SyncGenerator): Generate missing attributes
- Loading branch information
1 parent
3056a4b
commit 72ac37e
Showing
10 changed files
with
339 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/Uno.UWPSyncGenerator/AttributeGeneration/AttributeDataClassComparer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#nullable enable | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal sealed class AttributeDataClassComparer : IEqualityComparer<AttributeData> | ||
{ | ||
public static AttributeDataClassComparer Instance { get; } = new(); | ||
|
||
private AttributeDataClassComparer() | ||
{ | ||
} | ||
|
||
public bool Equals(AttributeData? x, AttributeData? y) | ||
{ | ||
return x?.AttributeClass?.ToString() == y?.AttributeClass?.ToString(); | ||
} | ||
|
||
public int GetHashCode([DisallowNull] AttributeData obj) => obj.AttributeClass?.ToString()?.GetHashCode() ?? 0; | ||
} |
50 changes: 50 additions & 0 deletions
50
src/Uno.UWPSyncGenerator/AttributeGeneration/AttributeDescriptionBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#nullable enable | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal abstract class AttributeDescriptionBase : IAttributeDescription | ||
{ | ||
private protected abstract bool CanHandle(string fullyQualifiedAttributeName); | ||
|
||
public string? TryGenerateCodeFromAttributeData(AttributeData attributeData) | ||
{ | ||
var attributeName = attributeData.AttributeClass?.ToString(); | ||
if (attributeName is null || !CanHandle(attributeName)) | ||
{ | ||
return null; | ||
} | ||
|
||
var parameters = TryGenerateAttributeParametersCommon(attributeData); | ||
if (parameters is null) | ||
{ | ||
return null; | ||
} | ||
else if (parameters.Length == 0) | ||
{ | ||
return $"[global::{attributeName}]"; | ||
} | ||
else | ||
{ | ||
return $"[global::{attributeName}({parameters})]"; | ||
} | ||
} | ||
|
||
private string? TryGenerateAttributeParametersCommon(AttributeData attributeData) | ||
{ | ||
if (attributeData.ConstructorArguments.Length == 0 && attributeData.NamedArguments.Length == 0) | ||
{ | ||
return string.Empty; | ||
} | ||
|
||
return TryGenerateAttributeParameters(attributeData); | ||
} | ||
|
||
/// <summary> | ||
/// Given <see cref="AttributeData"/>, try to generate parameters. If the current instance doesn't handle | ||
/// the given <paramref name="attributeData"/>, return null. | ||
/// This method is not called when both ConstructorArguments and NamedArguments are empty. | ||
/// </summary> | ||
protected abstract string? TryGenerateAttributeParameters(AttributeData attributeData); | ||
} |
80 changes: 80 additions & 0 deletions
80
src/Uno.UWPSyncGenerator/AttributeGeneration/AttributeUsageAttributeDescription.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#nullable enable | ||
|
||
using System; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal class AttributeUsageAttributeDescription : AttributeDescriptionBase | ||
{ | ||
protected override string? TryGenerateAttributeParameters(AttributeData attributeData) | ||
{ | ||
// The .Single() below is to assert we have a single constructor arguments, ie, AttributeTargets. | ||
// This adds confidence that we are not ignoring any constructor arguments. | ||
var attributeTargets = GetAttributeTargetsString((AttributeTargets)attributeData.ConstructorArguments.Single().Value!); | ||
|
||
// For some reason, attribute.ConstructorArguments.Single().Value can be "zero" for some attributes, e.g, OverridableAttribute. | ||
// From documentation: https://learn.microsoft.com/en-us/uwp/api/windows.foundation.metadata.overridableattribute?view=winrt-16299 | ||
// This is `System.AttributeTargets.InterfaceImpl`, but there is no such member in AttributeTargets, so it's probably not .NET-related. | ||
// We ignore adding the attribute for this case. | ||
if (attributeTargets.Length > 1) | ||
{ | ||
var allowMultiple = false; | ||
var isInherited = true; | ||
foreach (var namedArgument in attributeData.NamedArguments) | ||
{ | ||
if (namedArgument.Key.Equals("AllowMultiple", StringComparison.Ordinal)) | ||
{ | ||
allowMultiple = (bool)namedArgument.Value.Value!; | ||
} | ||
else if (namedArgument.Key.Equals("Inherited", StringComparison.Ordinal)) | ||
{ | ||
isInherited = (bool)namedArgument.Value.Value!; | ||
} | ||
else | ||
{ | ||
throw new InvalidOperationException($"Unexpected named argument '{namedArgument.Key}' for 'AttributeUsageAttribute'"); | ||
} | ||
} | ||
|
||
return $"{attributeTargets}, Inherited = {isInherited.ToString().ToLowerInvariant()}, AllowMultiple = {allowMultiple.ToString().ToLowerInvariant()}"; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private static string GetAttributeTargetsString(AttributeTargets valueToConvert) | ||
{ | ||
var isFirst = true; | ||
var result = ""; | ||
var values = Enum.GetValues(typeof(AttributeTargets)).Cast<AttributeTargets>().OrderByDescending(a => (int)a); | ||
foreach (var value in values) | ||
{ | ||
if ((value & valueToConvert) == value) | ||
{ | ||
if (isFirst) | ||
{ | ||
result = $"global::System.AttributeTargets.{value}"; | ||
} | ||
else | ||
{ | ||
result += $" | global::System.AttributeTargets.{value}"; | ||
} | ||
|
||
isFirst = false; | ||
valueToConvert = (AttributeTargets)(valueToConvert - value); | ||
} | ||
} | ||
|
||
if (valueToConvert != 0) | ||
{ | ||
throw new InvalidOperationException("Something went wrong.."); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private protected override bool CanHandle(string fullyQualifiedAttributeName) | ||
=> fullyQualifiedAttributeName == "System.AttributeUsageAttribute"; | ||
} |
21 changes: 21 additions & 0 deletions
21
src/Uno.UWPSyncGenerator/AttributeGeneration/BindableAttributeDescription.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#nullable enable | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal class BindableAttributeDescription : AttributeDescriptionBase | ||
{ | ||
protected override string? TryGenerateAttributeParameters(AttributeData attributeData) | ||
{ | ||
// This attribute doesn't have any constructor/named arguments. | ||
// It was already handled by TryGenerateAttributeParametersCommon in AttributeDescriptionBase. | ||
// We should never hit this code path, but if we did, just don't handle the attribute. | ||
return null; | ||
} | ||
|
||
private protected override bool CanHandle(string fullyQualifiedAttributeName) | ||
{ | ||
return fullyQualifiedAttributeName == "Windows" + ".UI.Xaml.Data.BindableAttribute"; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/Uno.UWPSyncGenerator/AttributeGeneration/ContentPropertyAttributeDescription.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#nullable enable | ||
|
||
using System; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal sealed class ContentPropertyAttributeDescription : AttributeDescriptionBase | ||
{ | ||
protected override string? TryGenerateAttributeParameters(AttributeData attributeData) | ||
{ | ||
if (attributeData.ConstructorArguments.IsEmpty && !attributeData.NamedArguments.IsEmpty) | ||
{ | ||
return $"Name = \"{(string)attributeData.NamedArguments.Single().Value.Value!}\""; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private protected override bool CanHandle(string fullyQualifiedAttributeName) | ||
{ | ||
return fullyQualifiedAttributeName is "Windows" + ".UI.Xaml.Markup.ContentPropertyAttribute" or "Microsoft.UI.Xaml.Markup.ContentPropertyAttribute"; | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Uno.UWPSyncGenerator/AttributeGeneration/DeprecatedAttributeDescription.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#nullable enable | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal class DeprecatedAttributeDescription : IAttributeDescription | ||
{ | ||
public string? TryGenerateCodeFromAttributeData(AttributeData attributeData) | ||
{ | ||
if (attributeData.AttributeClass?.ToString() == "Windows.Foundation.Metadata.DeprecatedAttribute") | ||
{ | ||
return "// This type is deprecated. Consider not implementing it."; | ||
} | ||
|
||
return null; | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Uno.UWPSyncGenerator/AttributeGeneration/FlagsAttributeDescription.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#nullable enable | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal sealed class FlagsAttributeDescription : AttributeDescriptionBase | ||
{ | ||
protected override string? TryGenerateAttributeParameters(AttributeData attributeData) | ||
{ | ||
// This attribute doesn't have any constructor/named arguments. | ||
// It was already handled by TryGenerateAttributeParametersCommon in AttributeDescriptionBase. | ||
// We should never hit this code path, but if we did, just don't handle the attribute. | ||
return null; | ||
} | ||
|
||
private protected override bool CanHandle(string fullyQualifiedAttributeName) => fullyQualifiedAttributeName == "System.FlagsAttribute"; | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Uno.UWPSyncGenerator/AttributeGeneration/IAttributeDescription.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#nullable enable | ||
|
||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Uno.UWPSyncGenerator.AttributeGeneration; | ||
|
||
internal interface IAttributeDescription | ||
{ | ||
/// <summary> | ||
/// Given an <see cref="AttributeData"/>, return a string representing the C# code for the attribute. If | ||
/// the given <paramref name="attributeData"/> can't be handled by this attribute description instance, returns null. | ||
/// </summary> | ||
string? TryGenerateCodeFromAttributeData(AttributeData attributeData); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters