File: EditAndContinue\Helpers\EditingTestBase.vb
Web Access
Project: ..\..\..\src\EditorFeatures\VisualBasicTest\Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.UnitTests.vbproj (Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.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.IO
Imports Microsoft.CodeAnalysis.Differencing
Imports Microsoft.CodeAnalysis.EditAndContinue
Imports Microsoft.CodeAnalysis.EditAndContinue.Contracts
Imports Microsoft.CodeAnalysis.EditAndContinue.UnitTests
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EditAndContinue
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests
 
    Public MustInherit Class EditingTestBase
        Inherits BasicTestBase
 
        Public Shared ReadOnly ReloadableAttributeSrc As String = "
Imports System.Runtime.CompilerServices
Namespace System.Runtime.CompilerServices
    Class CreateNewOnMetadataUpdateAttribute
        Inherits Attribute
    End Class
End Namespace
"
 
        Friend Shared Function CreateAnalyzer() As VisualBasicEditAndContinueAnalyzer
            Return New VisualBasicEditAndContinueAnalyzer()
        End Function
 
        Public Enum MethodKind
            Regular
            Async
            Iterator
        End Enum
 
        Public Shared Function GetResource(keyword As String) As String
            Select Case keyword
                Case "Enum"
                    Return FeaturesResources.enum_
                Case "Class"
                    Return FeaturesResources.class_
                Case "Structure"
                    Return VBFeaturesResources.structure_
                Case "Module"
                    Return VBFeaturesResources.module_
                Case "Interface"
                    Return FeaturesResources.interface_
                Case "Delegate"
                    Return FeaturesResources.delegate_
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(keyword)
            End Select
        End Function
 
        Friend Shared NoSemanticEdits As SemanticEditDescription() = Array.Empty(Of SemanticEditDescription)
 
        Friend Overloads Shared Function Diagnostic(rudeEditKind As RudeEditKind, squiggle As String, ParamArray arguments As String()) As RudeEditDiagnosticDescription
            Return New RudeEditDiagnosticDescription(rudeEditKind, squiggle, arguments, firstLine:=Nothing)
        End Function
 
        Friend Shared Function SemanticEdit(kind As SemanticEditKind,
                                            symbolProvider As Func(Of Compilation, ISymbol),
                                            syntaxMap As IEnumerable(Of KeyValuePair(Of TextSpan, TextSpan)),
                                            Optional partialType As String = Nothing,
                                            Optional deletedSymbolContainerProvider As Func(Of Compilation, ISymbol) = Nothing) As SemanticEditDescription
            Return New SemanticEditDescription(
                kind,
                symbolProvider,
                If(partialType Is Nothing, Nothing, Function(c As Compilation) CType(c.GetMember(partialType), ITypeSymbol)),
                syntaxMap,
                hasSyntaxMap:=syntaxMap IsNot Nothing,
                deletedSymbolContainerProvider)
        End Function
 
        Friend Shared Function SemanticEdit(kind As SemanticEditKind,
                                            symbolProvider As Func(Of Compilation, ISymbol),
                                            Optional partialType As String = Nothing,
                                            Optional preserveLocalVariables As Boolean = False,
                                            Optional deletedSymbolContainerProvider As Func(Of Compilation, ISymbol) = Nothing) As SemanticEditDescription
            Return New SemanticEditDescription(
                kind,
                symbolProvider,
                If(partialType Is Nothing, Nothing, Function(c As Compilation) CType(c.GetMember(partialType), ITypeSymbol)),
                syntaxMap:=Nothing,
                hasSyntaxMap:=preserveLocalVariables,
                deletedSymbolContainerProvider)
        End Function
 
        Friend Shared Function DeletedSymbolDisplay(kind As String, displayName As String) As String
            Return String.Format(FeaturesResources.member_kind_and_name, kind, displayName)
        End Function
 
        Friend Shared Function DocumentResults(
            Optional activeStatements As ActiveStatementsDescription = Nothing,
            Optional semanticEdits As SemanticEditDescription() = Nothing,
            Optional diagnostics As RudeEditDiagnosticDescription() = Nothing) As DocumentAnalysisResultsDescription
            Return New DocumentAnalysisResultsDescription(activeStatements, semanticEdits, lineEdits:=Nothing, diagnostics)
        End Function
 
        Private Shared Function GetDocumentFilePath(documentIndex As Integer) As String
            Return Path.Combine(TempRoot.Root, documentIndex.ToString() & ".vb")
        End Function
 
        Private Shared Function ParseSource(markedSource As String, Optional documentIndex As Integer = 0) As SyntaxTree
            Return SyntaxFactory.ParseSyntaxTree(
                ActiveStatementsDescription.ClearTags(markedSource),
                VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest),
                path:=GetDocumentFilePath(documentIndex))
        End Function
 
        Friend Shared Function GetTopEdits(src1 As String, src2 As String, Optional documentIndex As Integer = 0) As EditScript(Of SyntaxNode)
            Dim tree1 = ParseSource(src1, documentIndex)
            Dim tree2 = ParseSource(src2, documentIndex)
 
            tree1.GetDiagnostics().Verify()
            tree2.GetDiagnostics().Verify()
 
            Dim match = SyntaxComparer.TopLevel.ComputeMatch(tree1.GetRoot(), tree2.GetRoot())
            Return match.GetTreeEdits()
        End Function
 
        Public Shared Function GetTopEdits(methodEdits As EditScript(Of SyntaxNode)) As EditScript(Of SyntaxNode)
            Dim oldMethodSource = methodEdits.Match.OldRoot.ToFullString()
            Dim newMethodSource = methodEdits.Match.NewRoot.ToFullString()
 
            Return GetTopEdits(WrapMethodBodyWithClass(oldMethodSource), WrapMethodBodyWithClass(newMethodSource))
        End Function
 
        Friend Shared Function GetMethodEdits(src1 As String, src2 As String, Optional methodKind As MethodKind = MethodKind.Regular) As EditScript(Of SyntaxNode)
            Dim match = GetMethodMatch(src1, src2, methodKind)
            Return match.GetTreeEdits()
        End Function
 
        Friend Shared Function GetMethodMatch(src1 As String, src2 As String, Optional methodKind As MethodKind = MethodKind.Regular) As Match(Of SyntaxNode)
            Dim m1 = MakeMethodBody(src1, methodKind)
            Dim m2 = MakeMethodBody(src2, methodKind)
 
            Dim diagnostics = New ArrayBuilder(Of RudeEditDiagnostic)()
 
            Dim oldHasStateMachineSuspensionPoint = False, newHasStateMachineSuspensionPoint = False
            Dim match = CreateAnalyzer().GetTestAccessor().ComputeBodyMatch(m1, m2, Array.Empty(Of AbstractEditAndContinueAnalyzer.ActiveNode)(), diagnostics, oldHasStateMachineSuspensionPoint, newHasStateMachineSuspensionPoint)
            Dim needsSyntaxMap = oldHasStateMachineSuspensionPoint AndAlso newHasStateMachineSuspensionPoint
 
            Assert.Equal(methodKind <> MethodKind.Regular, needsSyntaxMap)
 
            If methodKind = MethodKind.Regular Then
                Assert.Empty(diagnostics)
            End If
 
            Return match
        End Function
 
        Public Shared Function GetMethodMatches(src1 As String,
                                                src2 As String,
                                                Optional kind As MethodKind = MethodKind.Regular) As IEnumerable(Of KeyValuePair(Of SyntaxNode, SyntaxNode))
            Dim methodMatch = GetMethodMatch(src1, src2, kind)
            Return EditAndContinueTestHelpers.GetMethodMatches(CreateAnalyzer(), methodMatch)
        End Function
 
        Public Shared Function ToMatchingPairs(match As Match(Of SyntaxNode)) As MatchingPairs
            Return EditAndContinueTestHelpers.ToMatchingPairs(match)
        End Function
 
        Public Shared Function ToMatchingPairs(matches As IEnumerable(Of KeyValuePair(Of SyntaxNode, SyntaxNode))) As MatchingPairs
            Return EditAndContinueTestHelpers.ToMatchingPairs(matches)
        End Function
 
        Friend Shared Function MakeMethodBody(bodySource As String, Optional stateMachine As MethodKind = MethodKind.Regular) As SyntaxNode
            Dim source = WrapMethodBodyWithClass(bodySource, stateMachine)
 
            Dim tree = ParseSource(source)
            Dim root = tree.GetRoot()
            tree.GetDiagnostics().Verify()
 
            Dim declaration = DirectCast(DirectCast(root, CompilationUnitSyntax).Members(0), ClassBlockSyntax).Members(0)
            Return SyntaxFactory.SyntaxTree(declaration).GetRoot()
        End Function
 
        Private Shared Function WrapMethodBodyWithClass(bodySource As String, Optional kind As MethodKind = MethodKind.Regular) As String
            Select Case kind
                Case MethodKind.Iterator
                    Return "Class C" & vbLf & "Iterator Function F() As IEnumerable(Of Integer)" & vbLf & bodySource & " : End Function : End Class"
 
                Case MethodKind.Async
                    Return "Class C" & vbLf & "Async Function F() As Task(Of Integer)" & vbLf & bodySource & " : End Function : End Class"
 
                Case Else
                    Return "Class C" & vbLf & "Sub F()" & vbLf & bodySource & " : End Sub : End Class"
            End Select
        End Function
 
        Friend Shared Function GetActiveStatements(oldSource As String, newSource As String, Optional flags As ActiveStatementFlags() = Nothing, Optional documentIndex As Integer = 0) As ActiveStatementsDescription
            Return New ActiveStatementsDescription(oldSource, newSource, Function(source) SyntaxFactory.ParseSyntaxTree(source, path:=GetDocumentFilePath(documentIndex)), flags)
        End Function
 
        Friend Shared Function GetSyntaxMap(oldSource As String, newSource As String) As SyntaxMapDescription
            Return New SyntaxMapDescription(oldSource, newSource)
        End Function
    End Class
End Namespace