// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp.Extensions; using static SyntaxFactory; internal static class ITypeParameterSymbolExtensions { public static SyntaxList<TypeParameterConstraintClauseSyntax> GenerateConstraintClauses( this ImmutableArray<ITypeParameterSymbol> typeParameters) { return typeParameters.AsEnumerable().GenerateConstraintClauses(); } public static SyntaxList<TypeParameterConstraintClauseSyntax> GenerateConstraintClauses( this IEnumerable<ITypeParameterSymbol> typeParameters) { using var _ = ArrayBuilder<TypeParameterConstraintClauseSyntax>.GetInstance(out var clauses); foreach (var typeParameter in typeParameters) AddConstraintClauses(clauses, typeParameter); return [.. clauses]; } private static void AddConstraintClauses( ArrayBuilder<TypeParameterConstraintClauseSyntax> clauses, ITypeParameterSymbol typeParameter) { using var _ = ArrayBuilder<TypeParameterConstraintSyntax>.GetInstance(out var constraints); if (typeParameter.HasReferenceTypeConstraint) { constraints.Add(ClassOrStructConstraint(SyntaxKind.ClassConstraint)); } else if (typeParameter.HasUnmanagedTypeConstraint) { constraints.Add(TypeConstraint(IdentifierName("unmanaged"))); } else if (typeParameter.HasValueTypeConstraint) { constraints.Add(ClassOrStructConstraint(SyntaxKind.StructConstraint)); } else if (typeParameter.HasNotNullConstraint) { constraints.Add(TypeConstraint(IdentifierName("notnull"))); } var constraintTypes = typeParameter.ConstraintTypes.Where(t => t.TypeKind == TypeKind.Class).Concat( typeParameter.ConstraintTypes.Where(t => t.TypeKind == TypeKind.Interface).Concat( typeParameter.ConstraintTypes.Where(t => t.TypeKind is not TypeKind.Class and not TypeKind.Interface))); foreach (var type in constraintTypes) { if (type.SpecialType != SpecialType.System_Object) constraints.Add(TypeConstraint(type.GenerateTypeSyntax())); } if (typeParameter.HasConstructorConstraint) constraints.Add(ConstructorConstraint()); if (typeParameter.AllowsRefLikeType) { // "allows ref struct" anti-constraint must be last constraints.Add(AllowsConstraintClause([RefStructConstraint()])); } if (constraints.Count == 0) return; clauses.Add(TypeParameterConstraintClause( typeParameter.Name.ToIdentifierName(), [.. constraints])); } } |