From 0e878b145690645c91eabf033d3838dbdcbe17f7 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 23 Aug 2016 12:06:17 -0400 Subject: [PATCH] Share implementation of ImplementAbstractClass. --- .../CSharpFeaturesResources.Designer.cs | 9 -- .../Portable/CSharpFeaturesResources.resx | 3 - .../ImplementAbstractClassCodeFixProvider.cs | 77 +-------------- ...ctImplementAbstractClassCodeFixProvider.cs | 95 +++++++++++++++++++ src/Features/Core/Portable/Features.csproj | 3 +- .../Portable/FeaturesResources.Designer.cs | 9 ++ .../Core/Portable/FeaturesResources.resx | 3 + .../ImplementAbstractClassCodeFixProvider.vb | 76 +-------------- .../Portable/VBFeaturesResources.Designer.vb | 11 +-- .../Portable/VBFeaturesResources.resx | 3 - 10 files changed, 119 insertions(+), 170 deletions(-) create mode 100644 src/Features/Core/Portable/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs index d39049e9764..5922c22010c 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs @@ -395,15 +395,6 @@ internal class CSharpFeaturesResources { } } - /// - /// Looks up a localized string similar to Implement Abstract Class. - /// - internal static string Implement_Abstract_Class { - get { - return ResourceManager.GetString("Implement_Abstract_Class", resourceCulture); - } - } - /// /// Looks up a localized string similar to <implicit array creation>. /// diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index a6ead4e6be7..f59d3a746bc 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -117,9 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Implement Abstract Class - Inline temporary variable diff --git a/src/Features/CSharp/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.cs index aaceb986a87..83e96d329c2 100644 --- a/src/Features/CSharp/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.cs @@ -1,90 +1,21 @@ // 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.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixes.ImplementAbstractClass; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.ImplementAbstractClass; -using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.ImplementAbstractClass { [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.ImplementAbstractClass), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateType)] - internal class ImplementAbstractClassCodeFixProvider : CodeFixProvider + internal class ImplementAbstractClassCodeFixProvider : + AbstractImplementAbstractClassCodeFixProvider { private const string CS0534 = nameof(CS0534); // 'Program' does not implement inherited abstract member 'Foo.bar()' - public sealed override ImmutableArray FixableDiagnosticIds => - ImmutableArray.Create(CS0534); - - public sealed override FixAllProvider GetFixAllProvider() => - WellKnownFixAllProviders.BatchFixer; - - 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 as ClassDeclarationSyntax; - if (classNode == null) - { - return; - } - - var service = document.GetLanguageService(); - - if (await service.CanImplementAbstractClassAsync( - document, - classNode, - cancellationToken).ConfigureAwait(false)) - { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - - var classSymbol = semanticModel.GetDeclaredSymbol(classNode); - 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 CSharpFeaturesResources.Implement_Abstract_Class + ";" + - assemblyName + ";" + - abstractTypeFullyQualifiedName; - } - - private Task ImplementAbstractClassAsync( - Document document, ClassDeclarationSyntax classNode, CancellationToken cancellationToken) - { - var service = document.GetLanguageService(); - return service.ImplementAbstractClassAsync(document, classNode, cancellationToken); - } - - private class MyCodeAction : CodeAction.DocumentChangeAction + public ImplementAbstractClassCodeFixProvider() : base(CS0534) { - public MyCodeAction(Func> createChangedDocument, string id) : - base(CSharpFeaturesResources.Implement_Abstract_Class, createChangedDocument, id) - { - } } } } \ No newline at end of file diff --git a/src/Features/Core/Portable/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs new file mode 100644 index 00000000000..2a5de8341d0 --- /dev/null +++ b/src/Features/Core/Portable/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -0,0 +1,95 @@ +// 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) + { + } + } + } +} \ No newline at end of file diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index 3e52b207222..c86072923b3 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -119,6 +119,7 @@ + @@ -652,4 +653,4 @@ - + \ No newline at end of file diff --git a/src/Features/Core/Portable/FeaturesResources.Designer.cs b/src/Features/Core/Portable/FeaturesResources.Designer.cs index 8ee89a72d4a..7eceaeb0f24 100644 --- a/src/Features/Core/Portable/FeaturesResources.Designer.cs +++ b/src/Features/Core/Portable/FeaturesResources.Designer.cs @@ -1314,6 +1314,15 @@ internal class FeaturesResources { } } + /// + /// Looks up a localized string similar to Implement Abstract Class. + /// + internal static string Implement_Abstract_Class { + get { + return ResourceManager.GetString("Implement_Abstract_Class", resourceCulture); + } + } + /// /// Looks up a localized string similar to Implement interface. /// diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index e81918e9544..ebc539cc6c7 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -1061,4 +1061,7 @@ This version used in: {2} (Unknown) + + Implement Abstract Class + \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.vb index d664eb420d5..20e53680248 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/ImplementAbstractClass/ImplementAbstractClassCodeFixProvider.vb @@ -1,87 +1,21 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -Imports System.Collections.Immutable -Imports System.Threading Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.ImplementAbstractClass Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeFixes.ImplementAbstractClass Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.ImplementAbstractClass Friend Class ImplementAbstractClassCodeFixProvider - Inherits CodeFixProvider + Inherits AbstractImplementAbstractClassCodeFixProvider(Of ClassBlockSyntax) Friend Const BC30610 As String = "BC30610" ' Class 'foo' must either be declared 'MustInherit' or override the following inherited 'MustOverride' member(s): - Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) - Get - Return ImmutableArray.Create(BC30610) - End Get - End Property - - Public NotOverridable Overrides Function GetFixAllProvider() As FixAllProvider - Return WellKnownFixAllProviders.BatchFixer - End Function - - Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task - Dim cancellationToken = context.CancellationToken - Dim document = context.Document - - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - - Dim token = root.FindToken(context.Span.Start) - If Not token.Span.IntersectsWith(context.Span) Then - Return - End If - - Dim classNode = token.GetAncestors(Of ClassBlockSyntax)() _ - .FirstOrDefault(Function(c) c.Span.IntersectsWith(context.Span)) - - If classNode Is Nothing Then - Return - End If - - Dim service = document.GetLanguageService(Of IImplementAbstractClassService)() - - If Await service.CanImplementAbstractClassAsync( - document, classNode, cancellationToken).ConfigureAwait(False) Then - - Dim model = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) - Dim classSymbol = model.GetDeclaredSymbol(classNode) - - Dim typeName = classSymbol.BaseType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) - Dim id = GetCodeActionId(classSymbol.BaseType.ContainingAssembly.Name, typeName) - context.RegisterCodeFix( - New MyCodeAction( - Function(c) ImplementAbstractClassAsync(document, classNode, c), - id), - context.Diagnostics) - Return - End If - End Function - - Friend Shared Function GetCodeActionId(assemblyName As String, abstractTypeFullyQualifiedName As String) As String - Return VBFeaturesResources.Implement_Abstract_Class + ";" + - assemblyName + ";" + - abstractTypeFullyQualifiedName - End Function - - Private Function ImplementAbstractClassAsync( - document As Document, classBlock As ClassBlockSyntax, cancellationToken As CancellationToken) As Task(Of Document) - Dim service = document.GetLanguageService(Of IImplementAbstractClassService)() - Return service.ImplementAbstractClassAsync(document, classBlock, cancellationToken) - End Function - - Private Class MyCodeAction - Inherits CodeAction.DocumentChangeAction - - Public Sub New(createChangedDocument As Func(Of CancellationToken, Task(Of Document)), id As String) - MyBase.New(VBFeaturesResources.Implement_Abstract_Class, createChangedDocument, id) - End Sub - End Class + Public Sub New() + MyBase.New(BC30610) + End Sub End Class End Namespace \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb index e13c9fc4cc4..bba803109ba 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb @@ -1141,16 +1141,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources "ocedure", resourceCulture) End Get End Property - - ''' - ''' Looks up a localized string similar to Implement Abstract Class. - ''' - Friend ReadOnly Property Implement_Abstract_Class() As String - Get - Return ResourceManager.GetString("Implement_Abstract_Class", resourceCulture) - End Get - End Property - + ''' ''' Looks up a localized string similar to Implicit member access can't be included in the selection without containing statement. ''' diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index 91ad0beaaaf..079ff97243d 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -210,9 +210,6 @@ Mid statement - - Implement Abstract Class - Fix Incorrect Function Return Type -- GitLab