File: CodeFixes\CodeFixServiceTests.vb
Web Access
Project: ..\..\..\src\EditorFeatures\Test2\Microsoft.CodeAnalysis.EditorFeatures2.UnitTests.vbproj (Microsoft.CodeAnalysis.EditorFeatures2.UnitTests)
' 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.
 
Imports System.Collections.Immutable
Imports System.Composition
Imports System.Diagnostics.CodeAnalysis
Imports System.Reflection
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Imports Microsoft.CodeAnalysis.Editor.UnitTests
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.ErrorLogger
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Roslyn.Utilities
 
Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests
 
    <[UseExportProvider]>
    <Trait(Traits.Feature, Traits.Features.Diagnostics)>
    Public Class CodeFixServiceTests
 
        Private Shared ReadOnly s_compositionWithMockDiagnosticUpdateSourceRegistrationService As TestComposition = EditorTestCompositions.EditorFeatures _
            .AddExcludedPartTypes(GetType(IDiagnosticUpdateSourceRegistrationService)) _
            .AddParts(GetType(MockDiagnosticUpdateSourceRegistrationService))
 
        Private ReadOnly _assemblyLoader As IAnalyzerAssemblyLoader = New InMemoryAssemblyLoader()
 
        Public Function CreateAnalyzerFileReference(ByVal fullPath As String) As AnalyzerFileReference
            Return New AnalyzerFileReference(fullPath, _assemblyLoader)
        End Function
 
        <Fact>
        Public Async Function TestProjectCodeFix() As Task
            Dim test = <Workspace>
                           <Project Language="C#" CommonReferences="true">
                               <Document FilePath="Test.cs">
                                        class Goo { }
                                    </Document>
                           </Project>
                       </Workspace>
 
            Using workspace = TestWorkspace.Create(test, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService)
                Dim workspaceDiagnosticAnalyzer = New WorkspaceDiagnosticAnalyzer()
                Dim workspaceCodeFixProvider = New WorkspaceCodeFixProvider()
 
                Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(workspaceDiagnosticAnalyzer))
                workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference}))
 
                Dim project = workspace.CurrentSolution.Projects(0)
 
                Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)())
                Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)())
                Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)
                Dim logger = SpecializedCollections.SingletonEnumerable(New Lazy(Of IErrorLoggerService)(Function() workspace.Services.GetService(Of IErrorLoggerService)))
                Dim codefixService = New CodeFixService(
                    diagnosticService,
                    logger,
                    {New Lazy(Of CodeFixProvider, Mef.CodeChangeProviderMetadata)(
                        Function() workspaceCodeFixProvider,
                        New Mef.CodeChangeProviderMetadata(New Dictionary(Of String, Object)() From {{"Name", "C#"}, {"Languages", {LanguageNames.CSharp}}}))},
                    SpecializedCollections.EmptyEnumerable(Of Lazy(Of IConfigurationFixProvider, Mef.CodeChangeProviderMetadata)))
 
                ' Verify available diagnostics
                Dim document = project.Documents.Single()
                Dim diagnostics = Await diagnosticService.GetDiagnosticsForSpanAsync(document,
                    (Await document.GetSyntaxRootAsync()).FullSpan)
 
                Assert.Equal(1, diagnostics.Count())
 
                ' Verify available codefix with a global fixer
                Dim fixes = Await codefixService.GetFixesAsync(
                    document,
                    (Await document.GetSyntaxRootAsync()).FullSpan,
                    CodeActionOptions.DefaultProvider,
                    isBlocking:=False,
                    CancellationToken.None)
 
                Assert.Equal(0, fixes.Count())
 
                ' Verify available codefix with a global fixer + a project fixer
                ' We will use this assembly as a project fixer provider.
                Dim _assembly = Assembly.GetExecutingAssembly()
                Dim projectAnalyzerReference = CreateAnalyzerFileReference(_assembly.Location)
 
                Dim projectAnalyzerReferences = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference)
                project = project.WithAnalyzerReferences(projectAnalyzerReferences)
                document = project.Documents.Single()
                fixes = Await codefixService.GetFixesAsync(
                    document,
                    (Await document.GetSyntaxRootAsync()).FullSpan,
                    CodeActionOptions.DefaultProvider,
                    isBlocking:=False,
                    CancellationToken.None)
                Assert.Equal(1, fixes.Count())
 
                ' Remove a project analyzer
                project = project.RemoveAnalyzerReference(projectAnalyzerReference)
                document = project.Documents.Single()
                fixes = Await codefixService.GetFixesAsync(
                    document,
                    (Await document.GetSyntaxRootAsync()).FullSpan,
                    CodeActionOptions.DefaultProvider,
                    isBlocking:=False,
                    CancellationToken.None)
 
                Assert.Equal(0, fixes.Count())
            End Using
        End Function
 
        <Fact>
        Public Async Function TestDifferentLanguageProjectCodeFix() As Task
            Dim test = <Workspace>
                           <Project Language="Visual Basic" CommonReferences="true">
                               <Document FilePath="Test.vb">
                                        Class Goo
                                        End Class
                                    </Document>
                           </Project>
                       </Workspace>
 
            Using workspace = TestWorkspace.Create(test, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService)
                Dim workspaceDiagnosticAnalyzer = New WorkspaceDiagnosticAnalyzer()
                Dim workspaceCodeFixProvider = New WorkspaceCodeFixProvider()
 
                Dim analyzerReference = New AnalyzerImageReference(ImmutableArray.Create(Of DiagnosticAnalyzer)(workspaceDiagnosticAnalyzer))
                workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference}))
 
                Dim project = workspace.CurrentSolution.Projects(0)
 
                Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)())
                Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)())
                Dim analyzer = diagnosticService.CreateIncrementalAnalyzer(workspace)
                Dim logger = SpecializedCollections.SingletonEnumerable(New Lazy(Of IErrorLoggerService)(Function() workspace.Services.GetService(Of IErrorLoggerService)))
                Dim codefixService = New CodeFixService(
                    diagnosticService,
                    logger,
                    {New Lazy(Of CodeFixProvider, Mef.CodeChangeProviderMetadata)(
                        Function() workspaceCodeFixProvider,
                        New Mef.CodeChangeProviderMetadata(New Dictionary(Of String, Object)() From {{"Name", "C#"}, {"Languages", {LanguageNames.CSharp}}}))},
                    SpecializedCollections.EmptyEnumerable(Of Lazy(Of IConfigurationFixProvider, Mef.CodeChangeProviderMetadata)))
 
                ' Verify available diagnostics
                Dim document = project.Documents.Single()
                Dim diagnostics = Await diagnosticService.GetDiagnosticsForSpanAsync(document,
                    (Await document.GetSyntaxRootAsync()).FullSpan)
 
                Assert.Equal(1, diagnostics.Count())
 
                ' Verify no codefix with a global fixer
                Dim fixes = Await codefixService.GetFixesAsync(
                    document,
                    (Await document.GetSyntaxRootAsync()).FullSpan,
                    CodeActionOptions.DefaultProvider,
                    isBlocking:=False,
                    CancellationToken.None)
 
                Assert.Equal(0, fixes.Count())
 
                ' Verify no codefix with a global fixer + a project fixer
                ' We will use this assembly as a project fixer provider.
                Dim _assembly = Assembly.GetExecutingAssembly()
                Dim projectAnalyzerReference = CreateAnalyzerFileReference(_assembly.Location)
 
                Dim projectAnalyzerReferences = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference)
                project = project.WithAnalyzerReferences(projectAnalyzerReferences)
                document = project.Documents.Single()
                fixes = Await codefixService.GetFixesAsync(
                    document,
                    (Await document.GetSyntaxRootAsync()).FullSpan,
                    CodeActionOptions.DefaultProvider,
                    isBlocking:=False,
                    CancellationToken.None)
 
                Assert.Equal(0, fixes.Count())
            End Using
        End Function
 
        Private Class WorkspaceDiagnosticAnalyzer
            Inherits AbstractDiagnosticAnalyzer
 
            Public ReadOnly Descriptor As DiagnosticDescriptor = New DiagnosticDescriptor("TEST1111",
                                                                                          "WorkspaceDiagnosticDescription",
                                                                                          "WorkspaceDiagnosticMessage",
                                                                                          "WorkspaceDiagnosticCategory",
                                                                                          DiagnosticSeverity.Warning,
                                                                                          isEnabledByDefault:=True)
 
            Public Overrides ReadOnly Property DiagDescriptor As DiagnosticDescriptor
                Get
                    Return Descriptor
                End Get
            End Property
        End Class
 
        Private MustInherit Class AbstractDiagnosticAnalyzer
            Inherits DiagnosticAnalyzer
 
            Public MustOverride ReadOnly Property DiagDescriptor As DiagnosticDescriptor
 
            Public Overrides ReadOnly Property SupportedDiagnostics As ImmutableArray(Of DiagnosticDescriptor)
                Get
                    Return ImmutableArray.Create(DiagDescriptor)
                End Get
            End Property
 
            Public Overrides Sub Initialize(context As AnalysisContext)
                context.RegisterSymbolAction(AddressOf AnalyzeSymbol, SymbolKind.NamedType)
            End Sub
 
            Public Sub AnalyzeSymbol(context As SymbolAnalysisContext)
                context.ReportDiagnostic(Diagnostic.Create(DiagDescriptor, context.Symbol.Locations.First(), context.Symbol.Locations.Skip(1)))
            End Sub
 
        End Class
 
        <ExportCodeFixProvider(LanguageNames.CSharp, Name:="WorkspaceCodeFixProvider"), [Shared]>
        Private Class WorkspaceCodeFixProvider
            Inherits CodeFixProvider
 
            <ImportingConstructor>
            <SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification:="Used in test code: https://github.com/dotnet/roslyn/issues/42814")>
            Public Sub New()
            End Sub
 
            Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String)
                Get
                    Return ImmutableArray.Create("TEST0000")
                End Get
            End Property
 
            Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task
                Contract.ThrowIfFalse(context.Document.Project.Language = LanguageNames.CSharp)
                Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False)
 
#Disable Warning RS0005
                context.RegisterCodeFix(CodeAction.Create("FIX_TEST0000", Function(ct) Task.FromResult(context.Document.WithSyntaxRoot(root))), context.Diagnostics)
#Enable Warning RS0005
            End Function
        End Class
 
        <ExportCodeFixProvider(LanguageNames.CSharp, Name:="ProjectCodeFixProvider"), [Shared]>
        Public Class ProjectCodeFixProvider
            Inherits CodeFixProvider
 
            <ImportingConstructor>
            <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
            Public Sub New()
            End Sub
 
            Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String)
                Get
                    Return ImmutableArray.Create("TEST1111")
                End Get
            End Property
 
            Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task
                Contract.ThrowIfFalse(context.Document.Project.Language = LanguageNames.CSharp)
                Dim root = Await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(False)
 
#Disable Warning RS0005
                context.RegisterCodeFix(CodeAction.Create("FIX_TEST1111", Function(ct) Task.FromResult(context.Document.WithSyntaxRoot(root))), context.Diagnostics)
#Enable Warning RS0005
            End Function
        End Class
    End Class
End Namespace