public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); // TODO: Replace the following code with your own analysis, generating a CodeAction for each fix to suggest var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; // Find the type declaration identified by the diagnostic. var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType <EnumDeclarationSyntax>().First(); var model = await context.Document.GetSemanticModelAsync(); var values = EnumValuesUtility.GetEnumValues(declaration, model); var offendingFieldDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType <EnumMemberDeclarationSyntax>().Single(); // Register a code action that will invoke the fix. context.RegisterCodeFix( CodeAction.Create( title: CodeFixResources.ChangeToNextBinaryValueTitle, createChangedSolution: c => ChangeEnumValueAsync(context.Document, offendingFieldDeclaration, values, model, c), equivalenceKey: nameof(CodeFixResources.ChangeToNextBinaryValueTitle)), diagnostic); if (diagnostic.Id == FlagEnumAnalyzer.EnumValueIsZeroId) { RegisterAppendAttributeCodefix <NoneAttribute>( context, CodeFixResources.AddNoneAttribute, nameof(CodeFixResources.AddNoneAttribute), diagnostic, offendingFieldDeclaration, model); } else { RegisterAppendAttributeCodefix <CombinedFlagsAttribute>( context, CodeFixResources.AddCombinedFlagsAttribute, nameof(CodeFixResources.AddCombinedFlagsAttribute), diagnostic, offendingFieldDeclaration, model); } }
private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context) { // TODO: Replace the following code with your own analysis, generating Diagnostic objects for any issues you find var semanticModel = context.SemanticModel; if (context.Node is EnumDeclarationSyntax enumDeclaration) { var symbol = (ITypeSymbol)semanticModel.GetDeclaredSymbol(enumDeclaration); if (symbol.TypeKind == TypeKind.Enum) { var attributes = symbol.GetAttributes(); if (attributes.Any(x => x.AttributeClass.Name == nameof(FlagsAttribute))) { var takenValues = new HashSet <int>(); foreach (var value in enumDeclaration.Members) { var model = semanticModel.GetDeclaredSymbol(value); var valueAttributes = model.GetAttributes(); if (!valueAttributes.Any(x => x.AttributeClass.Name == nameof(CombinedFlagsAttribute))) { if (EnumValuesUtility.IsPowerOfTwo((int)model.ConstantValue) && !takenValues.Contains((int)model.ConstantValue)) { if (model.ConstantValue is 0 && !valueAttributes.Any(x => x.AttributeClass.Name == nameof(NoneAttribute))) { context.ReportDiagnostic(Diagnostic.Create(EnumValueIsZero, value.GetLocation(), model.Name, nameof(NoneAttribute))); } takenValues.Add((int)model.ConstantValue); } else { context.ReportDiagnostic(Diagnostic.Create(EnumValueIsNotPowerOfTwo, value.GetLocation(), model.Name, nameof(CombinedFlagsAttribute))); } } } } } } }