internal static IFieldSymbol FindEnumDefaultField(INamedTypeSymbol enumSymbol) { if (enumSymbol == null) { throw new ArgumentNullException(nameof(enumSymbol)); } if (enumSymbol.EnumUnderlyingType == null) { throw new ArgumentException($"'{enumSymbol}' is not an enumeration.", nameof(enumSymbol)); } foreach (ISymbol symbol in enumSymbol.GetMembers()) { if (symbol.Kind == SymbolKind.Field) { var fieldSymbol = (IFieldSymbol)symbol; if (fieldSymbol.HasConstantValue && SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol) == 0) { return(fieldSymbol); } } } return(default(IFieldSymbol)); }
private static async Task <Document> DeclareExplicitValueAsync( Document document, EnumDeclarationSyntax enumDeclaration, INamedTypeSymbol enumSymbol, ImmutableArray <ulong> values, SemanticModel semanticModel, CancellationToken cancellationToken) { bool isFlags = enumSymbol.HasAttribute(MetadataNames.System_FlagsAttribute); List <ulong> reservedValues = values.ToList(); SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members; SeparatedSyntaxList <EnumMemberDeclarationSyntax> newMembers = members; for (int i = 0; i < members.Count; i++) { if (members[i].EqualsValue == null) { IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(members[i], cancellationToken); ulong?value = null; if (isFlags) { Optional <ulong> optional = FlagsUtility <ulong> .Instance.GetUniquePowerOfTwo(reservedValues); if (optional.HasValue && ConvertHelpers.CanConvert(optional.Value, enumSymbol.EnumUnderlyingType.SpecialType)) { value = optional.Value; } } else { value = SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol); } if (value != null) { reservedValues.Add(value.Value); EqualsValueClauseSyntax equalsValue = EqualsValueClause(NumericLiteralExpression(value.Value, enumSymbol.EnumUnderlyingType.SpecialType)); EnumMemberDeclarationSyntax newMember = members[i].WithEqualsValue(equalsValue); newMembers = newMembers.ReplaceAt(i, newMember); } } } EnumDeclarationSyntax newEnumDeclaration = enumDeclaration.WithMembers(newMembers); return(await document.ReplaceNodeAsync(enumDeclaration, newEnumDeclaration, cancellationToken).ConfigureAwait(false)); }
private static Task <Document> RefactorAsync( Document document, EnumDeclarationSyntax enumDeclaration, SeparatedSyntaxListSelection <EnumMemberDeclarationSyntax> selectedMembers, INamedTypeSymbol enumSymbol, string name, SemanticModel semanticModel, CancellationToken cancellationToken) { ExpressionSyntax expression = null; EnumMemberDeclarationSyntax lastMember = null; using (IEnumerator <EnumMemberDeclarationSyntax> en = GetMembersToCombine().GetEnumerator()) { if (en.MoveNext()) { lastMember = en.Current; expression = IdentifierName(en.Current.Identifier.WithoutTrivia()); while (en.MoveNext()) { expression = BitwiseOrExpression( IdentifierName(en.Current.Identifier.WithoutTrivia()), expression); } } } EnumMemberDeclarationSyntax newEnumMember = EnumMemberDeclaration( Identifier(name).WithRenameAnnotation(), EqualsValueClause(expression)); EnumDeclarationSyntax newEnumDeclaration = enumDeclaration .WithMembers(enumDeclaration.Members.Insert(selectedMembers.UnderlyingList.IndexOf(lastMember) + 1, newEnumMember)); return(document.ReplaceNodeAsync(enumDeclaration, newEnumDeclaration, cancellationToken)); IEnumerable <EnumMemberDeclarationSyntax> GetMembersToCombine() { for (int i = selectedMembers.Count - 1; i >= 0; i--) { IFieldSymbol symbol = semanticModel.GetDeclaredSymbol(selectedMembers[i], cancellationToken); if (symbol.HasConstantValue) { ulong value = SymbolUtility.GetEnumValueAsUInt64(symbol.ConstantValue, enumSymbol); if (!FlagsUtility <ulong> .Instance.IsComposite(value)) { yield return(selectedMembers[i]); } } } } }
private static Task <Document> RefactorAsync( Document document, EnumDeclarationSyntax enumDeclaration, INamedTypeSymbol enumSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { ulong value = 0; SpecialType numericType = enumSymbol.EnumUnderlyingType.SpecialType; IEnumerable <EnumMemberDeclarationSyntax> newMembers = (enumSymbol.HasAttribute(MetadataNames.System_FlagsAttribute)) ? enumDeclaration.Members.Select(CreateNewFlagsMember) : enumDeclaration.Members.Select(CreateNewMember); EnumDeclarationSyntax newEnumDeclaration = enumDeclaration.WithMembers(newMembers.ToSeparatedSyntaxList()); return(document.ReplaceNodeAsync(enumDeclaration, newEnumDeclaration, cancellationToken)); EnumMemberDeclarationSyntax CreateNewFlagsMember(EnumMemberDeclarationSyntax enumMember) { if (!ConvertHelpers.CanConvert(value, numericType)) { return(enumMember); } IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(enumMember, cancellationToken); if (fieldSymbol.HasConstantValue && FlagsUtility <ulong> .Instance.IsComposite(SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol))) { return(enumMember); } EnumMemberDeclarationSyntax newEnumMember = CreateNewEnumMember(enumMember, value, numericType); value = (value == 0) ? 1 : value * 2; return(newEnumMember); } EnumMemberDeclarationSyntax CreateNewMember(EnumMemberDeclarationSyntax enumMember) { if (!ConvertHelpers.CanConvert(value, numericType)) { return(enumMember); } EnumMemberDeclarationSyntax newEnumMember = CreateNewEnumMember(enumMember, value, numericType); value++; return(newEnumMember); } }
private static async Task <Document> RefactorAsync( Document document, EnumDeclarationSyntax enumDeclaration, IEnumerable <EnumMemberDeclarationSyntax> enumMembers, bool keepCompositeValue, CancellationToken cancellationToken) { SemanticModel semanticModel = null; if (keepCompositeValue) { semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumDeclaration, cancellationToken); keepCompositeValue = enumSymbol.HasAttribute(MetadataNames.System_FlagsAttribute); } IEnumerable <TextChange> textChanges = enumMembers .Where(enumMember => { ExpressionSyntax expression = enumMember.EqualsValue?.Value; if (expression == null) { return(false); } if (keepCompositeValue && !(expression is LiteralExpressionSyntax)) { IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(enumMember, cancellationToken); if (!fieldSymbol.HasConstantValue) { return(false); } ulong value = SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, fieldSymbol.ContainingType); if (FlagsUtility <ulong> .Instance.IsComposite(value)) { return(false); } } return(true); }) .Select(f => new TextChange(TextSpan.FromBounds(f.Identifier.Span.End, f.EqualsValue.Span.End), "")); return(await document.WithTextChangesAsync(textChanges, cancellationToken).ConfigureAwait(false)); }
public static OneOrMany <EnumFieldSymbolInfo> GetConstituentFields(object value, INamedTypeSymbol enumType) { EnumSymbolInfo enumInfo = EnumSymbolInfo.Create(enumType); ulong convertedValue = SymbolUtility.GetEnumValueAsUInt64(value, enumType); if (!enumType.HasAttribute(MetadataNames.System_FlagsAttribute) || convertedValue == 0) { return(OneOrMany.Create(FindField(enumInfo, convertedValue))); } return(GetConstituentFields(convertedValue, enumInfo)); }
private static ImmutableArray <ulong> GetConstantValues(INamedTypeSymbol enumSymbol) { ImmutableArray <ulong> .Builder values = ImmutableArray.CreateBuilder <ulong>(); foreach (ISymbol member in enumSymbol.GetMembers()) { if (member.Kind == SymbolKind.Field) { var fieldSymbol = (IFieldSymbol)member; if (fieldSymbol.HasConstantValue) { values.Add(SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol)); } } } return(values.ToImmutableArray()); }
public static void ComputeRefactoring( RefactoringContext context, EnumDeclarationSyntax enumDeclaration, SeparatedSyntaxListSelection <EnumMemberDeclarationSyntax> selectedMembers, SemanticModel semanticModel) { INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumDeclaration, context.CancellationToken); if (enumSymbol?.HasAttribute(MetadataNames.System_FlagsAttribute) != true) { return; } ImmutableArray <ulong> constantValues = selectedMembers .Select(f => semanticModel.GetDeclaredSymbol(f, context.CancellationToken)) .Where(f => f.HasConstantValue) .Select(f => SymbolUtility.GetEnumValueAsUInt64(f.ConstantValue, enumSymbol)) .ToImmutableArray(); Optional <ulong> optionalValue = FlagsUtility <ulong> .Instance.TryCompose(constantValues); if (!optionalValue.HasValue) { return; } if (IsValueDefined(enumSymbol, optionalValue)) { return; } string name = NameGenerator.Default.EnsureUniqueMemberName( string.Concat(selectedMembers.Select(f => f.Identifier.ValueText)), enumSymbol); context.RegisterRefactoring( $"Generate enum member '{name}'", ct => RefactorAsync(context.Document, enumDeclaration, selectedMembers, name, ct), RefactoringIdentifiers.GenerateCombinedEnumMember); }
private static ImmutableArray <ulong> GetExplicitValues( EnumDeclarationSyntax enumDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) { ImmutableArray <ulong> .Builder values = ImmutableArray.CreateBuilder <ulong>(); foreach (EnumMemberDeclarationSyntax member in enumDeclaration.Members) { ExpressionSyntax value = member.EqualsValue?.Value; if (value != null) { IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(member, cancellationToken); if (fieldSymbol?.HasConstantValue == true) { values.Add(SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, fieldSymbol.ContainingType)); } } } return(values.ToImmutableArray()); }
public static void ComputeRefactoring( RefactoringContext context, EnumDeclarationSyntax enumDeclaration, SeparatedSyntaxListSelection <EnumMemberDeclarationSyntax> selectedMembers, SemanticModel semanticModel) { if (!enumDeclaration.AttributeLists.Any()) { return; } INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumDeclaration, context.CancellationToken); if (enumSymbol?.HasAttribute(MetadataNames.System_FlagsAttribute) != true) { return; } IEnumerable <(IFieldSymbol symbol, ulong value)> symbolsValues = selectedMembers .Select(f => semanticModel.GetDeclaredSymbol(f, context.CancellationToken)) .Where(f => f.HasConstantValue) .Select(f => (symbol: f, value: SymbolUtility.GetEnumValueAsUInt64(f.ConstantValue, enumSymbol))) .Where(f => !FlagsUtility <ulong> .Instance.IsComposite(f.value)); ImmutableArray <ulong> constantValues = symbolsValues.Select(f => f.value).ToImmutableArray(); if (constantValues.Length <= 1) { return; } Optional <ulong> optionalValue = FlagsUtility <ulong> .Instance.TryCompose(constantValues); if (!optionalValue.HasValue) { return; } if (IsValueDefined(optionalValue)) { return; } string name = NameGenerator.Default.EnsureUniqueEnumMemberName( string.Concat(symbolsValues.Select(f => f.symbol.Name)), enumSymbol); context.RegisterRefactoring( $"Generate member '{name}'", ct => RefactorAsync(context.Document, enumDeclaration, selectedMembers, enumSymbol, name, semanticModel, ct), RefactoringIdentifiers.GenerateCombinedEnumMember); bool IsValueDefined(object value) { foreach (ISymbol member in enumSymbol.GetMembers()) { if (member.Kind == SymbolKind.Field) { var fieldSymbol = (IFieldSymbol)member; if (fieldSymbol.HasConstantValue && object.Equals(fieldSymbol.ConstantValue, value)) { return(true); } } } return(false); } }
private static async Task <Document> DeclareExplicitValueAsync( Document document, EnumDeclarationSyntax enumDeclaration, INamedTypeSymbol enumSymbol, bool isFlags, bool useBitShift, ImmutableArray <ulong> values, SemanticModel semanticModel, CancellationToken cancellationToken) { List <ulong> reservedValues = values.ToList(); SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members; SeparatedSyntaxList <EnumMemberDeclarationSyntax> newMembers = members; for (int i = 0; i < members.Count; i++) { if (members[i].EqualsValue == null) { IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(members[i], cancellationToken); ulong?value = null; if (isFlags) { Optional <ulong> optional = FlagsUtility <ulong> .Instance.GetUniquePowerOfTwo(reservedValues); if (optional.HasValue && ConvertHelpers.CanConvertFromUInt64(optional.Value, enumSymbol.EnumUnderlyingType.SpecialType)) { value = optional.Value; } } else { value = SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol); } if (value != null) { reservedValues.Add(value.Value); ExpressionSyntax expression; if (useBitShift && value.Value > 1) { var power = (int)Math.Log(Convert.ToDouble(value.Value), 2); expression = LeftShiftExpression(NumericLiteralExpression(1), NumericLiteralExpression(power)); } else { expression = NumericLiteralExpression(value.Value, enumSymbol.EnumUnderlyingType.SpecialType); } EnumMemberDeclarationSyntax newMember = members[i].Update( members[i].AttributeLists, members[i].Modifiers, members[i].Identifier.WithoutTrailingTrivia(), EqualsValueClause(expression).WithTrailingTrivia(members[i].Identifier.TrailingTrivia)); newMembers = newMembers.ReplaceAt(i, newMember); } } } EnumDeclarationSyntax newEnumDeclaration = enumDeclaration.WithMembers(newMembers); return(await document.ReplaceNodeAsync(enumDeclaration, newEnumDeclaration, cancellationToken).ConfigureAwait(false)); }