/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTests.vb
241 строка
13 KB
Cyrus Najmabadi
Merge branch 'main' into simplifyCodeFix
12 сен 2025, 00:57
12 сен 2025, 00:57
a8b1b35
Код
Авторство
О чём код?
' 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.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Host Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.UnitTests Imports Microsoft.CodeAnalysis.UnitTests.Diagnostics Imports Roslyn.Utilities Imports Xunit.Abstractions Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics <[UseExportProvider]> Partial Public MustInherit Class AbstractCrossLanguageUserDiagnosticTests Private ReadOnly _outputHelper As ITestOutputHelper Protected Sub New(Optional outputHelper As ITestOutputHelper = Nothing) _outputHelper = outputHelper End Sub Protected Const DestinationDocument = "DestinationDocument" Private Shared ReadOnly s_compositionWithMockDiagnosticUpdateSourceRegistrationService As TestComposition = EditorTestCompositions.EditorFeatures _ .AddParts(GetType(WorkspaceTestLogger)) Private Shared ReadOnly s_composition As TestComposition = s_compositionWithMockDiagnosticUpdateSourceRegistrationService _ .AddParts(GetType(TestAddMetadataReferenceCodeActionOperationFactoryWorkspaceService)) Friend MustOverride Function CreateDiagnosticProviderAndFixer(workspace As Workspace, language As String) As (DiagnosticAnalyzer, CodeFixProvider) Protected Async Function TestMissing(definition As XElement) As Task Using workspace = EditorTestWorkspace.Create(definition, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) Dim diagnosticAndFix = Await GetDiagnosticAndFixAsync(workspace) Assert.Null(diagnosticAndFix) End Using End Function Protected Overridable Function MassageActions(actions As IList(Of CodeAction)) As IList(Of CodeAction) Return actions End Function Protected Shared Function FlattenActions(codeActions As IEnumerable(Of CodeAction)) As IList(Of CodeAction) Return codeActions?.SelectMany( Function(a) If(a.NestedActions.Length > 0, a.NestedActions.ToArray(), {a})).ToList() End Function Protected Async Function TestAsync(definition As XElement, Optional expected As String = Nothing, Optional codeActionIndex As Integer = 0, Optional verifyTokens As Boolean = True, Optional fileNameToExpected As Dictionary(Of String, String) = Nothing, Optional verifySolutions As Func(Of Solution, Solution, Task) = Nothing, Optional onAfterWorkspaceCreated As Func(Of EditorTestWorkspace, Task) = Nothing, Optional glyphTags As ImmutableArray(Of String) = Nothing) As Task Using workspace = EditorTestWorkspace.CreateWorkspace(definition, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) If _outputHelper IsNot Nothing Then workspace.Services.SolutionServices.SetWorkspaceTestOutput(_outputHelper) End If If onAfterWorkspaceCreated IsNot Nothing Then Await onAfterWorkspaceCreated(workspace) End If Dim diagnosticAndFix = Await GetDiagnosticAndFixAsync(workspace) Dim codeActions As IList(Of CodeAction) = diagnosticAndFix.Item2.Fixes.Select(Function(f) f.Action).ToList() codeActions = MassageActions(codeActions) Dim codeAction = codeActions(codeActionIndex) If Not glyphTags.IsDefault Then AssertEx.SetEqual(glyphTags, codeAction.Tags) End If Dim oldSolution = workspace.CurrentSolution Dim operations = Await codeAction.GetOperationsAsync(CancellationToken.None) For Each operation In operations If operation.ApplyDuringTests Then operation.Apply(workspace, CancellationToken.None) End If Next Dim updatedSolution = workspace.CurrentSolution If verifySolutions IsNot Nothing Then Await verifySolutions(oldSolution, updatedSolution) End If If expected Is Nothing AndAlso fileNameToExpected Is Nothing AndAlso verifySolutions Is Nothing Then Dim projectChanges = SolutionUtilities.GetSingleChangedProjectChanges(oldSolution, updatedSolution) Assert.Empty(projectChanges.GetChangedDocuments()) ElseIf expected IsNot Nothing Then Dim updatedDocument = SolutionUtilities.GetSingleChangedDocument(oldSolution, updatedSolution) Await VerifyAsync(expected, verifyTokens, updatedDocument) ElseIf fileNameToExpected IsNot Nothing Then For Each kvp In fileNameToExpected Dim updatedDocument = updatedSolution.Projects.SelectMany(Function(p) p.Documents).Single(Function(d) d.Name = kvp.Key) Await VerifyAsync(kvp.Value, verifyTokens, updatedDocument) Next End If End Using End Function Private Shared Async Function VerifyAsync(expected As String, verifyTokens As Boolean, updatedDocument As Document) As Task Dim actual = (Await updatedDocument.GetTextAsync()).ToString().Trim() If verifyTokens Then Utilities.AssertEx.TokensAreEqual(expected, actual, updatedDocument.Project.Language) Else AssertEx.Equal(expected, actual) End If End Function Friend Async Function GetDiagnosticAndFixAsync(workspace As EditorTestWorkspace) As Task(Of Tuple(Of Diagnostic, CodeFixCollection)) Return (Await GetDiagnosticAndFixesAsync(workspace)).FirstOrDefault() End Function Private Shared Function GetHostDocument(workspace As EditorTestWorkspace) As EditorTestHostDocument Dim hostDocument = workspace.Documents.First(Function(d) d.CursorPosition.HasValue) Return hostDocument End Function Public Shared Sub AddAnalyzerToWorkspace(workspace As Workspace, analyzer As DiagnosticAnalyzer) Dim analyzeReferences As AnalyzerReference() If analyzer IsNot Nothing Then analyzeReferences = {New AnalyzerImageReference(ImmutableArray.Create(analyzer))} Else ' create a serializable analyzer reference analyzeReferences = { New AnalyzerFileReference(DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.CSharp).GetType().Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile), New AnalyzerFileReference(DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(LanguageNames.VisualBasic).GetType().Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile) } End If workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(analyzeReferences)) End Sub Private Async Function GetDiagnosticAndFixesAsync(workspace As EditorTestWorkspace) As Task(Of IEnumerable(Of Tuple(Of Diagnostic, CodeFixCollection))) Dim hostDocument = GetHostDocument(workspace) Dim providerAndFixer = CreateDiagnosticProviderAndFixer(workspace, hostDocument.Project.Language) Dim fixer = providerAndFixer.Item2 AddAnalyzerToWorkspace(workspace, providerAndFixer.Item1) Dim result = New List(Of Tuple(Of Diagnostic, CodeFixCollection)) Dim docAndDiagnostics = Await GetDocumentAndDiagnosticsAsync(workspace) Dim document = docAndDiagnostics.Item1 Dim ids = New HashSet(Of String)(fixer.FixableDiagnosticIds) Dim diagnostics = docAndDiagnostics.Item2.Where(Function(d) ids.Contains(d.Id)).ToList() Dim tree = Await document.GetSyntaxTreeAsync() For Each diagnostic In diagnostics Dim fixes = New List(Of CodeFix) Dim context = New CodeFixContext(document, diagnostic, Sub(a, d) fixes.Add(New CodeFix(a, d)), CancellationToken.None) providerAndFixer.Item2.RegisterCodeFixesAsync(context).Wait() If fixes.Any() Then result.Add(Tuple.Create(diagnostic, New CodeFixCollection( fixer, diagnostic.Location.SourceSpan, fixes.ToImmutableArrayOrEmpty(), fixAllState:=Nothing, supportedScopes:=Nothing, ImmutableArray.Create(diagnostic)))) End If Next Return result End Function Private Shared Async Function GetDocumentAndDiagnosticsAsync(workspace As EditorTestWorkspace) As Task(Of Tuple(Of Document, IEnumerable(Of Diagnostic))) Dim hostDocument = GetHostDocument(workspace) Dim invocationBuffer = hostDocument.GetTextBuffer() Dim invocationPoint = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue AndAlso Not d.IsLinkFile).CursorPosition.Value Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim syntaxFacts = document.GetLanguageService(Of ISyntaxFactsService)() Dim root = Await document.GetSyntaxRootAsync() Dim start = syntaxFacts.GetContainingMemberDeclaration(root, invocationPoint) Dim result = Await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(workspace, document, start.FullSpan) '' currently, we don't test compilation level user diagnostic Return Tuple.Create(document, result.Where(Function(d) d.Location.SourceSpan.IntersectsWith(invocationPoint))) End Function Protected Async Function TestAddProjectReferenceAsync(xmlDefinition As XElement, expectedProjectReferenceFrom As String, expectedProjectReferenceTo As String, Optional index As Integer = 0) As Task Using workspace = EditorTestWorkspace.Create(xmlDefinition, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) Dim diagnosticAndFix = Await GetDiagnosticAndFixAsync(workspace) Dim codeAction = diagnosticAndFix.Item2.Fixes.ElementAt(index).Action Dim operations = Await codeAction.GetOperationsAsync(CancellationToken.None) Dim edit = operations.OfType(Of ApplyChangesOperation)().First() Dim addedProjectReference = SolutionUtilities.GetSingleAddedProjectReference(workspace.CurrentSolution, edit.ChangedSolution) Assert.Equal(expectedProjectReferenceFrom, addedProjectReference.Item1.Name) Dim projectTo = edit.ChangedSolution.GetProject(addedProjectReference.Item2.ProjectId) Assert.Equal(expectedProjectReferenceTo, projectTo.Name) End Using End Function Protected Async Function TestAddUnresolvedMetadataReferenceAsync(xmlDefinition As XElement, expectedProjectToReceiveReference As String, expectedAssemblyIdentity As String, Optional index As Integer = 0) As Task Using workspace = EditorTestWorkspace.Create(xmlDefinition, composition:=s_composition) Dim diagnosticAndFix = Await GetDiagnosticAndFixAsync(workspace) Dim codeAction = diagnosticAndFix.Item2.Fixes.ElementAt(index).Action Dim operations = Await codeAction.GetOperationsAsync(CancellationToken.None) Dim edit = operations.OfType(Of ApplyChangesOperation)().FirstOrDefault() Assert.Equal(Nothing, edit) Dim postOp = operations.OfType(Of TestAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.Operation).FirstOrDefault() Assert.NotEqual(Nothing, postOp) Assert.Equal(expectedAssemblyIdentity, postOp.AssemblyIdentity.GetDisplayName()) Assert.Equal(expectedProjectToReceiveReference, workspace.CurrentSolution.GetProject(postOp.ProjectId).Name) End Using End Function Protected Overridable Function GetNode(doc As Document, position As Integer) As SyntaxNode Return doc.GetSyntaxRootAsync().Result.FindToken(position).Parent End Function End Class End Namespace