|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | 3 | // See the LICENSE file in the project root for more information. |
4 | 4 |
|
| 5 | +using System; |
5 | 6 | using System.Collections.Generic; |
6 | 7 | using System.Diagnostics.Contracts; |
| 8 | +using System.Linq; |
7 | 9 | using Microsoft.CodeAnalysis; |
| 10 | +using Microsoft.CodeAnalysis.CSharp; |
| 11 | +using Microsoft.CodeAnalysis.CSharp.Syntax; |
| 12 | +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; |
8 | 13 |
|
9 | 14 | namespace Microsoft.Toolkit.Mvvm.SourceGenerators.Extensions |
10 | 15 | { |
@@ -36,5 +41,78 @@ properties.Value.Value is T argumentValue && |
36 | 41 |
|
37 | 42 | return false; |
38 | 43 | } |
| 44 | + |
| 45 | + /// <summary> |
| 46 | + /// Creates an <see cref="AttributeSyntax"/> node that is equivalent to the input <see cref="AttributeData"/> instance. |
| 47 | + /// </summary> |
| 48 | + /// <param name="attributeData">The input <see cref="AttributeData"/> instance to process.</param> |
| 49 | + /// <returns>An <see cref="AttributeSyntax"/> replicating the data in <paramref name="attributeData"/>.</returns> |
| 50 | + [Pure] |
| 51 | + public static AttributeSyntax AsAttributeSyntax(this AttributeData attributeData) |
| 52 | + { |
| 53 | + IdentifierNameSyntax attributeType = IdentifierName(attributeData.AttributeClass!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); |
| 54 | + AttributeArgumentSyntax[] arguments = |
| 55 | + attributeData.ConstructorArguments |
| 56 | + .Select(static arg => AttributeArgument(ToExpression(arg))).Concat( |
| 57 | + attributeData.NamedArguments |
| 58 | + .Select(static arg => |
| 59 | + AttributeArgument(ToExpression(arg.Value)) |
| 60 | + .WithNameEquals(NameEquals(IdentifierName(arg.Key))))).ToArray(); |
| 61 | + |
| 62 | + return Attribute(attributeType, AttributeArgumentList(SeparatedList(SeparatedList(arguments)))); |
| 63 | + |
| 64 | + static ExpressionSyntax ToExpression(TypedConstant arg) |
| 65 | + { |
| 66 | + if (arg.IsNull) |
| 67 | + { |
| 68 | + return LiteralExpression(SyntaxKind.NullLiteralExpression); |
| 69 | + } |
| 70 | + |
| 71 | + if (arg.Kind == TypedConstantKind.Array) |
| 72 | + { |
| 73 | + string elementType = ((IArrayTypeSymbol)arg.Type!).ElementType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); |
| 74 | + |
| 75 | + return |
| 76 | + ArrayCreationExpression( |
| 77 | + ArrayType(IdentifierName(elementType)) |
| 78 | + .AddRankSpecifiers(ArrayRankSpecifier(SingletonSeparatedList<ExpressionSyntax>(OmittedArraySizeExpression())))) |
| 79 | + .WithInitializer(InitializerExpression(SyntaxKind.ArrayInitializerExpression) |
| 80 | + .AddExpressions(arg.Values.Select(ToExpression).ToArray())); |
| 81 | + } |
| 82 | + |
| 83 | + switch ((arg.Kind, arg.Value)) |
| 84 | + { |
| 85 | + case (TypedConstantKind.Primitive, string text): |
| 86 | + return LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(text)); |
| 87 | + case (TypedConstantKind.Primitive, bool flag) when flag: |
| 88 | + return LiteralExpression(SyntaxKind.TrueLiteralExpression); |
| 89 | + case (TypedConstantKind.Primitive, bool): |
| 90 | + return LiteralExpression(SyntaxKind.FalseLiteralExpression); |
| 91 | + case (TypedConstantKind.Primitive, object value): |
| 92 | + return LiteralExpression(SyntaxKind.NumericLiteralExpression, value switch |
| 93 | + { |
| 94 | + byte b => Literal(b), |
| 95 | + char c => Literal(c), |
| 96 | + double d => Literal(d), |
| 97 | + float f => Literal(f), |
| 98 | + int i => Literal(i), |
| 99 | + long l => Literal(l), |
| 100 | + sbyte sb => Literal(sb), |
| 101 | + short sh => Literal(sh), |
| 102 | + uint ui => Literal(ui), |
| 103 | + ulong ul => Literal(ul), |
| 104 | + ushort ush => Literal(ush), |
| 105 | + _ => throw new ArgumentException() |
| 106 | + }); |
| 107 | + case (TypedConstantKind.Type, ITypeSymbol type): |
| 108 | + return TypeOfExpression(IdentifierName(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))); |
| 109 | + case (TypedConstantKind.Enum, object value): |
| 110 | + return CastExpression( |
| 111 | + IdentifierName(arg.Type!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)), |
| 112 | + LiteralExpression(SyntaxKind.NumericLiteralExpression, ParseToken(value.ToString()))); |
| 113 | + default: throw new ArgumentException(); |
| 114 | + } |
| 115 | + } |
| 116 | + } |
39 | 117 | } |
40 | 118 | } |
0 commit comments