static void AnalyzeStatement(SyntaxNodeAnalysisContext context)
        {
            var switchStatement = (SwitchStatementSyntax)context.Node;
            var semanticModel   = context.SemanticModel;

            if (!SwitchAnalysis.TryAnalyze(switchStatement, semanticModel, out var analysis))
            {
                return;
            }
            if (analysis.IsAllFound)
            {
                return;
            }

            context.ReportDiagnostic(
                Diagnostic.Create(
                    Rule,
                    switchStatement.SwitchKeyword.GetLocation(),
                    string.Join(", ", analysis.MissingEnumMembers.Select(c => $"'{c.Name}'"))
                    ));
        }
Example #2
0
        public static bool TryAnalyze(SwitchStatementSyntax switchStatement, SemanticModel semanticModel, out SwitchAnalysis analysis)
        {
            analysis = default;

            if (switchStatement.Expression == null)
            {
                return(false);
            }

            var typeSymbol = semanticModel.GetTypeInfo(switchStatement.Expression).Type;

            if (typeSymbol == null || typeSymbol.TypeKind != TypeKind.Enum)
            {
                return(false);
            }

            AnalyzeSections(switchStatement, semanticModel, out var foundEnumMembers, out var defaultSectionOrNull);

            var enumMembers =
                typeSymbol
                .GetMembers()
                .OfType <IFieldSymbol>()
                .Where(symbol => symbol.IsConst)
                .OrderBy(symbol => symbol.ConstantValue)
                .Select(symbol => new EnumMember(symbol, foundEnumMembers.Contains(symbol)))
                .ToImmutableArray();

            analysis =
                new SwitchAnalysis(
                    switchStatement,
                    semanticModel,
                    defaultSectionOrNull,
                    typeSymbol,
                    enumMembers
                    );
            return(true);
        }
Example #3
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var ct = context.CancellationToken;

            var diagnostic = context.Diagnostics.FirstOrDefault();

            if (diagnostic == null)
            {
                return;
            }

            var diagnosticSpan = diagnostic.Location.SourceSpan;

            var root = await context.Document.GetSyntaxRootAsync(ct).ConfigureAwait(false);

            if (root == null)
            {
                return;
            }

            var switchStatement =
                root
                .FindToken(diagnosticSpan.Start)
                .Parent
                .AncestorsAndSelf()
                .OfType <SwitchStatementSyntax>()
                .FirstOrDefault();

            if (switchStatement == null)
            {
                return;
            }

            var semanticModel = await context.Document.GetSemanticModelAsync(ct);

            if (semanticModel == null)
            {
                return;
            }

            if (!SwitchAnalysis.TryAnalyze(switchStatement, semanticModel, out var analysis))
            {
                return;
            }
            if (analysis.IsAllFound)
            {
                return;
            }

            context.RegisterCodeFix(
                CodeAction.Create(
                    diagnostic.Descriptor.Title.ToString(),
                    _ =>
                    Task.FromResult(
                        context.Document.WithSyntaxRoot(
                            root.ReplaceNode(
                                switchStatement,
                                analysis.Fix()
                                ))),
                    equivalenceKey: diagnostic.GetMessage()
                    ),
                diagnostic
                );
        }