private static void Analyze( SyntaxNodeAnalysisContext context, EnumMemberDeclarationSyntax member, ExpressionSyntax value, EnumFlagValueStyle style) { if (IsFlag(context, member)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.NormalizeFormatOfEnumFlagValue, value, (style == EnumFlagValueStyle.DecimalNumber) ? "Convert value to decimal number." : "Use '<<' operator."); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out EnumMemberDeclarationSyntax enumMemberDeclaration)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; switch (diagnostic.Id) { case DiagnosticIdentifiers.DeclareEnumValueAsCombinationOfNames: { CodeAction codeAction = CodeAction.Create( "Declare value as combination of names", ct => DeclareEnumValueAsCombinationOfNamesAsync(document, enumMemberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.DuplicateEnumValue: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var enumDeclaration = (EnumDeclarationSyntax)enumMemberDeclaration.Parent; IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(enumMemberDeclaration, context.CancellationToken); EnumFieldSymbolInfo enumFieldSymbolInfo = EnumFieldSymbolInfo.Create(fieldSymbol); string valueText = FindMemberByValue(enumDeclaration, enumFieldSymbolInfo, semanticModel, context.CancellationToken).Identifier.ValueText; CodeAction codeAction = CodeAction.Create( $"Change enum value to '{valueText}'", ct => ChangeEnumValueAsync(document, enumMemberDeclaration, valueText, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.NormalizeFormatOfEnumFlagValue: { EnumFlagValueStyle style = document.GetConfigOptions(enumMemberDeclaration.SyntaxTree).GetEnumFlagValueStyle(); if (style == EnumFlagValueStyle.ShiftOperator) { CodeAction codeAction = CodeAction.Create( "Use '<<' operator", ct => UseBitShiftOperatorAsync(document, enumMemberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else if (style == EnumFlagValueStyle.DecimalNumber) { CodeAction codeAction = CodeAction.Create( "Convert to decimal", ct => ConvertToDecimalNumberAsync(document, enumMemberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { throw new InvalidOperationException(); } break; } } }
private void AnalyzeEnumDeclaration(SyntaxNodeAnalysisContext context) { var enumDeclaration = (EnumDeclarationSyntax)context.Node; if (!enumDeclaration.AttributeLists.Any()) { return; } EnumFlagValueStyle style = context.GetEnumFlagValueStyle(); if (style == EnumFlagValueStyle.None) { return; } if (context.SemanticModel.GetDeclaredSymbol(enumDeclaration, context.CancellationToken) is not INamedTypeSymbol typeSymbol) { return; } if (typeSymbol.TypeKind != TypeKind.Enum) { return; } if (!typeSymbol.HasAttribute(MetadataNames.System_FlagsAttribute)) { return; } foreach (EnumMemberDeclarationSyntax member in enumDeclaration.Members) { ExpressionSyntax value = member.EqualsValue?.Value.WalkDownParentheses(); if (value != null) { if (value.IsKind(SyntaxKind.NumericLiteralExpression)) { var literalExpression = (LiteralExpressionSyntax)value; string text = literalExpression.Token.Text; if (style == EnumFlagValueStyle.DecimalNumber) { if (text.StartsWith("0b", StringComparison.OrdinalIgnoreCase) || text.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { Analyze(context, member, value, style); } } else if (style == EnumFlagValueStyle.ShiftOperator) { Analyze(context, member, value, style); } } else if (value.IsKind(SyntaxKind.LeftShiftExpression) && style == EnumFlagValueStyle.DecimalNumber) { Analyze(context, member, value, style); } } } }