File: ImplementAbstractClass\AbstractImplementAbstractClassCodeFixProvider.cs
Web Access
Project: ..\..\..\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// 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.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Microsoft.CodeAnalysis.ImplementAbstractClass
{
    internal abstract class AbstractImplementAbstractClassCodeFixProvider<TClassNode> : CodeFixProvider
        where TClassNode : SyntaxNode
    {
        public sealed override ImmutableArray<string> FixableDiagnosticIds { get; }
 
        public sealed override FixAllProvider GetFixAllProvider()
            => WellKnownFixAllProviders.BatchFixer;
 
        protected AbstractImplementAbstractClassCodeFixProvider(string diagnosticId)
            => FixableDiagnosticIds = ImmutableArray.Create(diagnosticId);
 
        protected abstract SyntaxToken GetClassIdentifier(TClassNode classNode);
 
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var cancellationToken = context.CancellationToken;
            var document = context.Document;
 
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
 
            var token = root.FindToken(context.Span.Start);
            if (!token.Span.IntersectsWith(context.Span))
                return;
 
            var classNode = token.Parent.GetAncestorOrThis<TClassNode>();
            if (classNode == null)
                return;
 
            var data = await ImplementAbstractClassData.TryGetDataAsync(
                document, classNode, GetClassIdentifier(classNode), context.Options.GetImplementTypeGenerationOptions(document.Project.Services), cancellationToken).ConfigureAwait(false);
            if (data == null)
                return;
 
            var abstractClassType = data.AbstractClassType;
            var id = GetCodeActionId(abstractClassType.ContainingAssembly.Name, abstractClassType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
            context.RegisterCodeFix(
                CodeAction.Create(
                    FeaturesResources.Implement_abstract_class,
                    c => data.ImplementAbstractClassAsync(throughMember: null, canDelegateAllMembers: null, c),
                    id),
                context.Diagnostics);
 
            foreach (var (through, canDelegateAllMembers) in data.GetDelegatableMembers())
            {
                id = GetCodeActionId(
                    abstractClassType.ContainingAssembly.Name,
                    abstractClassType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                    through.Name);
 
                context.RegisterCodeFix(
                    CodeAction.Create(
                        string.Format(FeaturesResources.Implement_through_0, through.Name),
                        c => data.ImplementAbstractClassAsync(through, canDelegateAllMembers, c),
                        id),
                    context.Diagnostics);
            }
        }
 
        private static string GetCodeActionId(string assemblyName, string abstractTypeFullyQualifiedName, string through = "")
            => FeaturesResources.Implement_abstract_class + ";" + assemblyName + ";" + abstractTypeFullyQualifiedName + ";" + through;
    }
}