File: AbstractPopulateSwitchStatementCodeFixProvider.cs
Web Access
Project: ..\..\..\src\CodeStyle\Core\CodeFixes\Microsoft.CodeAnalysis.CodeStyle.Fixes.csproj (Microsoft.CodeAnalysis.CodeStyle.Fixes)
// 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.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.PopulateSwitch
{
    internal abstract class AbstractPopulateSwitchStatementCodeFixProvider<
        TSwitchSyntax, TSwitchArmSyntax, TMemberAccessExpression> :
        AbstractPopulateSwitchCodeFixProvider<
            ISwitchOperation, TSwitchSyntax, TSwitchArmSyntax, TMemberAccessExpression>
        where TSwitchSyntax : SyntaxNode
        where TSwitchArmSyntax : SyntaxNode
        where TMemberAccessExpression : SyntaxNode
    {
        protected AbstractPopulateSwitchStatementCodeFixProvider()
            : base(IDEDiagnosticIds.PopulateSwitchStatementDiagnosticId)
        {
        }
 
        protected sealed override void FixOneDiagnostic(
            Document document, SyntaxEditor editor, SemanticModel semanticModel,
            bool addCases, bool addDefaultCase, bool onlyOneDiagnostic,
            bool hasMissingCases, bool hasMissingDefaultCase,
            TSwitchSyntax switchNode, ISwitchOperation switchOperation)
        {
            var newSwitchNode = UpdateSwitchNode(
                editor, semanticModel, addCases, addDefaultCase,
                hasMissingCases, hasMissingDefaultCase,
                switchNode, switchOperation).WithAdditionalAnnotations(Formatter.Annotation);
 
            if (onlyOneDiagnostic)
            {
                // If we're only fixing up one issue in this document, then also make sure we 
                // didn't cause any braces to be imbalanced when we added members to the switch.
                // Note: i'm only doing this for the single case because it feels too complex
                // to try to support this during fix-all.
                var root = editor.OriginalRoot;
                AddMissingBraces(document, ref root, ref switchNode);
 
                var newRoot = root.ReplaceNode(switchNode, newSwitchNode);
                editor.ReplaceNode(editor.OriginalRoot, newRoot);
            }
            else
            {
                editor.ReplaceNode(switchNode, newSwitchNode);
            }
        }
 
        protected sealed override ITypeSymbol GetSwitchType(ISwitchOperation switchOperation)
            => switchOperation.Value.Type ?? throw ExceptionUtilities.Unreachable();
 
        protected sealed override ICollection<ISymbol> GetMissingEnumMembers(ISwitchOperation switchOperation)
            => PopulateSwitchStatementHelpers.GetMissingEnumMembers(switchOperation);
 
        protected sealed override bool HasNullSwitchArm(ISwitchOperation switchOperation)
            => PopulateSwitchStatementHelpers.HasNullSwitchArm(switchOperation);
 
        protected sealed override TSwitchSyntax InsertSwitchArms(SyntaxGenerator generator, TSwitchSyntax switchNode, int insertLocation, List<TSwitchArmSyntax> newArms)
            => (TSwitchSyntax)generator.InsertSwitchSections(switchNode, insertLocation, newArms);
 
        protected sealed override TSwitchArmSyntax CreateDefaultSwitchArm(SyntaxGenerator generator, Compilation compilation)
            => (TSwitchArmSyntax)generator.DefaultSwitchSection(new[] { generator.ExitSwitchStatement() });
 
        protected sealed override TSwitchArmSyntax CreateSwitchArm(SyntaxGenerator generator, Compilation compilation, TMemberAccessExpression caseLabel)
            => (TSwitchArmSyntax)generator.SwitchSection(caseLabel, new[] { generator.ExitSwitchStatement() });
 
        protected override TSwitchArmSyntax CreateNullSwitchArm(SyntaxGenerator generator, Compilation compilation)
            => (TSwitchArmSyntax)generator.SwitchSection(generator.NullLiteralExpression(), new[] { generator.ExitSwitchStatement() });
 
        protected sealed override int InsertPosition(ISwitchOperation switchStatement)
        {
            // If the last section has a default label, then we want to be above that.
            // Otherwise, we just get inserted at the end.
 
            var cases = switchStatement.Cases;
            if (cases.Length > 0)
            {
                var lastCase = cases.Last();
                if (lastCase.Clauses.Any(static c => c.CaseKind == CaseKind.Default))
                {
                    return cases.Length - 1;
                }
            }
 
            return cases.Length;
        }
    }
}