// ------------------------------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.Health.Extensions.BuildTimeCodeGenerator; internal static class TypeExtensions { /// /// Converts a to a . /// /// The type /// Whether the to qualify type names with "global::" /// A representing the type. public static TypeSyntax ToTypeSyntax(this Type t, bool useGlobalAlias = false) { if (t == typeof(void)) { return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)); } if (t.IsByRef) { return SyntaxFactory.RefType(t.GetElementType().ToTypeSyntax()); } if (t.IsGenericParameter) { return SyntaxFactory.IdentifierName(t.Name); } if (t.IsArray) { return SyntaxFactory.ArrayType( t.GetElementType().ToTypeSyntax(useGlobalAlias), SyntaxFactory.SingletonList( SyntaxFactory.ArrayRankSpecifier( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.OmittedArraySizeExpression())))); } if (t.IsPointer) { return SyntaxFactory.PointerType(t.GetElementType().ToTypeSyntax(useGlobalAlias)); } TypeSyntax qualification = t.IsNested ? t.DeclaringType.ToTypeSyntax(useGlobalAlias) : t.Namespace.Split('.') .Select(s => (NameSyntax)SyntaxFactory.IdentifierName(s)) .Aggregate((acc, next) => { // see if we should qualify with global:: NameSyntax left = useGlobalAlias && acc is IdentifierNameSyntax identifier ? SyntaxFactory.AliasQualifiedName(SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.GlobalKeyword)), identifier) : acc; return SyntaxFactory.QualifiedName(left, (SimpleNameSyntax)next); }); SimpleNameSyntax name = t.IsGenericType ? SyntaxFactory.GenericName(t.Name.Substring(0, t.Name.IndexOf('`', StringComparison.Ordinal))) .WithTypeArgumentList(SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(t.GenericTypeArguments.Select(typeArg => typeArg.ToTypeSyntax(useGlobalAlias))))) : SyntaxFactory.IdentifierName(t.Name); return SyntaxFactory.QualifiedName((NameSyntax)qualification, name); } /// /// Creates a closed generic type from the a generic type definition (like ) and type arguments (like ). /// /// The generic type definition /// Type arguments /// The generic type. public static TypeSyntax CreateGenericTypeFromGenericTypeDefinition(TypeSyntax genericTypeDefinition, params TypeSyntax[] typeArguments) { GenericNameSyntax openType = genericTypeDefinition.DescendantNodes().OfType().Single(); GenericNameSyntax closedType = openType.AddTypeArgumentListArguments(typeArguments); return genericTypeDefinition.ReplaceNode(openType, closedType); } }