microsoft/healthcare-shared-components
Publicmirrored from https://github.com/microsoft/healthcare-shared-componentsAvailable
tools/Microsoft.Health.Extensions.BuildTimeCodeGenerator/TypeExtensions.cs
86lines · modecode
| 1 | // ------------------------------------------------------------------------------------------------- |
| 2 | // Copyright (c) Microsoft Corporation. All rights reserved. |
| 3 | // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. |
| 4 | // ------------------------------------------------------------------------------------------------- |
| 5 | |
| 6 | using System; |
| 7 | using System.Collections.Generic; |
| 8 | using System.Linq; |
| 9 | using Microsoft.CodeAnalysis; |
| 10 | using Microsoft.CodeAnalysis.CSharp; |
| 11 | using Microsoft.CodeAnalysis.CSharp.Syntax; |
| 12 | |
| 13 | namespace Microsoft.Health.Extensions.BuildTimeCodeGenerator |
| 14 | { |
| 15 | internal static class TypeExtensions |
| 16 | { |
| 17 | /// <summary> |
| 18 | /// Converts a <see cref="Type"/> to a <see cref="TypeSyntax"/>. |
| 19 | /// </summary> |
| 20 | /// <param name="t">The type</param> |
| 21 | /// <param name="useGlobalAlias">Whether the to qualify type names with "global::"</param> |
| 22 | /// <returns>A <see cref="TypeSyntax"/> representing the type.</returns> |
| 23 | public static TypeSyntax ToTypeSyntax(this Type t, bool useGlobalAlias = false) |
| 24 | { |
| 25 | if (t == typeof(void)) |
| 26 | { |
| 27 | return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)); |
| 28 | } |
| 29 | |
| 30 | if (t.IsGenericParameter) |
| 31 | { |
| 32 | return SyntaxFactory.IdentifierName(t.Name); |
| 33 | } |
| 34 | |
| 35 | if (t.IsArray) |
| 36 | { |
| 37 | return SyntaxFactory.ArrayType( |
| 38 | t.GetElementType().ToTypeSyntax(useGlobalAlias), |
| 39 | SyntaxFactory.SingletonList( |
| 40 | SyntaxFactory.ArrayRankSpecifier( |
| 41 | SyntaxFactory.SingletonSeparatedList<ExpressionSyntax>( |
| 42 | SyntaxFactory.OmittedArraySizeExpression())))); |
| 43 | } |
| 44 | |
| 45 | if (t.IsPointer) |
| 46 | { |
| 47 | return SyntaxFactory.PointerType(t.GetElementType().ToTypeSyntax(useGlobalAlias)); |
| 48 | } |
| 49 | |
| 50 | TypeSyntax qualification = t.IsNested |
| 51 | ? t.DeclaringType.ToTypeSyntax(useGlobalAlias) |
| 52 | : t.Namespace.Split('.') |
| 53 | .Select(s => (NameSyntax)SyntaxFactory.IdentifierName(s)) |
| 54 | .Aggregate((acc, next) => |
| 55 | { |
| 56 | // see if we should qualify with global:: |
| 57 | NameSyntax left = useGlobalAlias && acc is IdentifierNameSyntax identifier |
| 58 | ? SyntaxFactory.AliasQualifiedName(SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.GlobalKeyword)), identifier) |
| 59 | : acc; |
| 60 | |
| 61 | return SyntaxFactory.QualifiedName(left, (SimpleNameSyntax)next); |
| 62 | }); |
| 63 | |
| 64 | SimpleNameSyntax name = t.IsGenericType |
| 65 | ? SyntaxFactory.GenericName(t.Name.Substring(0, t.Name.IndexOf('`', StringComparison.Ordinal))) |
| 66 | .WithTypeArgumentList(SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(t.GenericTypeArguments.Select(typeArg => typeArg.ToTypeSyntax(useGlobalAlias))))) |
| 67 | : (SimpleNameSyntax)SyntaxFactory.IdentifierName(t.Name); |
| 68 | |
| 69 | return SyntaxFactory.QualifiedName((NameSyntax)qualification, name); |
| 70 | } |
| 71 | |
| 72 | /// <summary> |
| 73 | /// Creates a closed generic type from the a generic type definition (like <see cref="IEnumerable{T}"/>) and type arguments (like <see cref="string"/>). |
| 74 | /// </summary> |
| 75 | /// <param name="genericTypeDefinition">The generic type definition</param> |
| 76 | /// <param name="typeArguments">Type arguments</param> |
| 77 | /// <returns>The generic type.</returns> |
| 78 | public static TypeSyntax CreateGenericTypeFromGenericTypeDefinition(TypeSyntax genericTypeDefinition, params TypeSyntax[] typeArguments) |
| 79 | { |
| 80 | GenericNameSyntax openType = genericTypeDefinition.DescendantNodes().OfType<GenericNameSyntax>().Single(); |
| 81 | GenericNameSyntax closedType = openType.AddTypeArgumentListArguments(typeArguments); |
| 82 | |
| 83 | return genericTypeDefinition.ReplaceNode(openType, closedType); |
| 84 | } |
| 85 | } |
| 86 | } |