// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.ImplementAbstractClass; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeFixes.ImplementAbstractClass { internal abstract class AbstractImplementAbstractClassCodeFixProvider : CodeFixProvider where TClassNode : SyntaxNode { public sealed override ImmutableArray FixableDiagnosticIds { get; } public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; protected AbstractImplementAbstractClassCodeFixProvider(string diagnosticId) { FixableDiagnosticIds = ImmutableArray.Create(diagnosticId); } public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var cancellationToken = context.CancellationToken; var document = context.Document; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(context.Span.Start); if (!token.Span.IntersectsWith(context.Span)) { return; } var classNode = token.Parent.GetAncestorOrThis(); if (classNode == null) { return; } var service = document.GetLanguageService(); var canImplement = await service.CanImplementAbstractClassAsync( document, classNode, cancellationToken).ConfigureAwait(false); if (!canImplement) { return; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var classSymbol = semanticModel.GetDeclaredSymbol(classNode) as INamedTypeSymbol; if (classSymbol == null) { return; } var abstractType = classSymbol.BaseType; var id = GetCodeActionId(abstractType.ContainingAssembly.Name, abstractType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); context.RegisterCodeFix( new MyCodeAction( c => ImplementAbstractClassAsync(document, classNode, c), id), context.Diagnostics); } // internal for testing purposes. internal static string GetCodeActionId(string assemblyName, string abstractTypeFullyQualifiedName) { return FeaturesResources.Implement_Abstract_Class + ";" + assemblyName + ";" + abstractTypeFullyQualifiedName; } private Task ImplementAbstractClassAsync( Document document, TClassNode classNode, CancellationToken cancellationToken) { var service = document.GetLanguageService(); return service.ImplementAbstractClassAsync(document, classNode, cancellationToken); } private class MyCodeAction : CodeAction.DocumentChangeAction { public MyCodeAction(Func> createChangedDocument, string id) : base(FeaturesResources.Implement_Abstract_Class, createChangedDocument, id) { } } } }