diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs b/src/Features/CSharp/Portable/CSharpFeaturesResources.Designer.cs index d39049e97648fa31041574fa384f0c5c76389adb..5922c22010c33fa5120f3dd537b6b3d0d677e145 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 a6ead4e6be7e94d315104d659ac6c96b116c6625..f59d3a746bcf7684f92e783e5966a209036929b0 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 aaceb986a8786d81030d4024522d2e4813582b46..83e96d329c23c3ffc3b88f485b9640eba4850543 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 0000000000000000000000000000000000000000..2a5de8341d0408635ab3477824e55b2c5d802042 --- /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 3e52b2072220449459c5d718ebb68575aaed2ccc..c86072923b3aa2e2293254ab7a28e4f6e89ede2d 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 8ee89a72d4a6a360efb8c075d61df66f0202ce6c..7eceaeb0f24765a29a708085600ab3f869117382 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 e81918e95442e27db02799edb242525bbf0c4299..ebc539cc6c7bec1ccafad20431dee7a58f2b80bd 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 d664eb420d53d6b0a416ee37797d1e626df99677..20e536802484b16c07d1ba0214c355fac8781f92 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 e13c9fc4cc4796ba5b1c5c52f710e8d98dd7cc24..bba803109ba8ae2729ad7508f1a6a818b0134b51 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 91ad0beaaaf19c936f18bcce9d1edbff07a84509..079ff97243d66e48cb91e3c9f9280bbce0b4a3d5 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