File: ChangeSignature\VisualBasicChangeSignatureService.vb
Web Access
Project: src\src\Features\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Features.vbproj (Microsoft.CodeAnalysis.VisualBasic.Features)
' 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.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.ChangeSignature
Imports Microsoft.CodeAnalysis.EditAndContinue
Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.FindSymbols
Imports Microsoft.CodeAnalysis.Formatting
Imports Microsoft.CodeAnalysis.Formatting.Rules
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageService
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory
 
Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature
    <ExportLanguageService(GetType(AbstractChangeSignatureService), LanguageNames.VisualBasic), [Shared]>
    Friend Class VisualBasicChangeSignatureService
        Inherits AbstractChangeSignatureService
 
        Private Shared ReadOnly _declarationKinds As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(
            SyntaxKind.SubStatement,
            SyntaxKind.FunctionStatement,
            SyntaxKind.SubNewStatement,
            SyntaxKind.PropertyStatement,
            SyntaxKind.DelegateSubStatement,
            SyntaxKind.DelegateFunctionStatement,
            SyntaxKind.EventStatement)
 
        Private Shared ReadOnly _declarationAndInvocableKinds As ImmutableArray(Of SyntaxKind) =
            _declarationKinds.Concat(ImmutableArray.Create(
                SyntaxKind.SubBlock,
                SyntaxKind.FunctionBlock,
                SyntaxKind.ConstructorBlock,
                SyntaxKind.PropertyBlock,
                SyntaxKind.InvocationExpression,
                SyntaxKind.EventBlock,
                SyntaxKind.ObjectCreationExpression))
 
        Private Shared ReadOnly _nodeKindsToIgnore As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(
            SyntaxKind.ImplementsClause)
 
        Private Shared ReadOnly _updatableNodeKinds As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(
            SyntaxKind.CrefReference,
            SyntaxKind.ImplementsClause,
            SyntaxKind.SubStatement,
            SyntaxKind.FunctionStatement,
            SyntaxKind.DelegateSubStatement,
            SyntaxKind.DelegateFunctionStatement,
            SyntaxKind.EventBlock,
            SyntaxKind.EventStatement,
            SyntaxKind.RaiseEventStatement,
            SyntaxKind.PropertyStatement,
            SyntaxKind.InvocationExpression,
            SyntaxKind.Attribute,
            SyntaxKind.ObjectCreationExpression,
            SyntaxKind.SubNewStatement,
            SyntaxKind.ConstructorBlock,
            SyntaxKind.SingleLineSubLambdaExpression,
            SyntaxKind.MultiLineSubLambdaExpression,
            SyntaxKind.SingleLineFunctionLambdaExpression,
            SyntaxKind.MultiLineFunctionLambdaExpression)
 
        Private Shared ReadOnly _updatableAncestorKinds As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(
            SyntaxKind.CrefReference,
            SyntaxKind.ImplementsClause,
            SyntaxKind.SubStatement,
            SyntaxKind.FunctionStatement,
            SyntaxKind.DelegateSubStatement,
            SyntaxKind.DelegateFunctionStatement,
            SyntaxKind.EventBlock,
            SyntaxKind.EventStatement,
            SyntaxKind.RaiseEventStatement,
            SyntaxKind.PropertyStatement,
            SyntaxKind.InvocationExpression,
            SyntaxKind.Attribute,
            SyntaxKind.ObjectCreationExpression,
            SyntaxKind.SubNewStatement,
            SyntaxKind.ConstructorBlock)
 
        Private ReadOnly s_createNewParameterSyntaxDelegate As Func(Of AddedParameter, ParameterSyntax) = AddressOf CreateNewParameterSyntax
        Private ReadOnly s_createNewCrefParameterSyntaxDelegate As Func(Of AddedParameter, CrefSignaturePartSyntax) = AddressOf CreateNewCrefParameterSyntax
 
        <ImportingConstructor>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New()
        End Sub
 
        Public Overrides Async Function GetInvocationSymbolAsync(
                document As Document,
                position As Integer,
                restrictToDeclarations As Boolean,
                cancellationToken As CancellationToken) As Task(Of (symbol As ISymbol, selectedIndex As Integer))
            Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False)
            Dim token = tree.GetRoot(cancellationToken).FindToken(If(position <> tree.Length, position, Math.Max(0, position - 1)))
 
            Dim matchingNode = GetMatchingNode(token.Parent, restrictToDeclarations)
 
            If matchingNode Is Nothing Then
                Return Nothing
            End If
 
            ' Don't show change-signature in the random whitespace/trivia for code.
            If Not matchingNode.Span.IntersectsWith(position) Then
                Return Nothing
            End If
 
            ' If we're actually on the declaration of some symbol, ensure that we're
            ' in a good location for that symbol (i.e. Not in the attributes or after the parameter list).
            If Not IsInSymbolHeader(matchingNode, position) Then
                Return Nothing
            End If
 
            Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
            Dim symbol = TryGetDeclaredSymbol(semanticModel, matchingNode, cancellationToken)
            If symbol IsNot Nothing Then
                Dim selectedIndex = TryGetSelectedIndexFromDeclaration(position, matchingNode)
                Return (symbol, selectedIndex)
            End If
 
            If matchingNode.Kind() = SyntaxKind.ObjectCreationExpression Then
                Dim objectCreation = DirectCast(matchingNode, ObjectCreationExpressionSyntax)
                If token.Parent.AncestorsAndSelf().Any(Function(a) a Is objectCreation.Type) Then
                    Dim typeSymbol = semanticModel.GetSymbolInfo(objectCreation.Type, cancellationToken).Symbol
                    If typeSymbol IsNot Nothing AndAlso typeSymbol.IsKind(SymbolKind.NamedType) AndAlso DirectCast(typeSymbol, ITypeSymbol).TypeKind = TypeKind.Delegate Then
                        Return (typeSymbol, 0)
                    End If
                End If
            End If
 
            Dim symbolInfo = semanticModel.GetSymbolInfo(matchingNode, cancellationToken)
            symbol = If(symbolInfo.Symbol, symbolInfo.CandidateSymbols.FirstOrDefault())
            Dim parameterIndex = 0
 
            ' If we're being called on an invocation and not a definition we need to find the selected argument index based on the original definition.
            Dim invocation = matchingNode.GetAncestorOrThis(Of InvocationExpressionSyntax)
            Dim argument = invocation?.ArgumentList?.Arguments.FirstOrDefault(Function(a) a.Span.Contains(position))
            If (argument IsNot Nothing) Then
                parameterIndex = GetParameterIndexFromInvocationArgument(argument, document, semanticModel, cancellationToken)
            End If
 
            Return (symbol, parameterIndex)
        End Function
 
        Private Shared Function TryGetSelectedIndexFromDeclaration(position As Integer, matchingNode As SyntaxNode) As Integer
            Dim parameters = matchingNode.ChildNodes().OfType(Of ParameterListSyntax)().SingleOrDefault()
            Return If(parameters Is Nothing, 0, GetParameterIndex(parameters.Parameters, position))
        End Function
 
        Private Shared Function GetMatchingNode(node As SyntaxNode, restrictToDeclarations As Boolean) As SyntaxNode
            Dim current = node
            While current IsNot Nothing
                If restrictToDeclarations Then
                    If _declarationKinds.Contains(current.Kind()) Then
                        Return current
                    End If
                Else
                    If _declarationAndInvocableKinds.Contains(current.Kind()) Then
                        Return current
                    End If
                End If
 
                current = current.Parent
            End While
 
            Return Nothing
        End Function
 
        Private Shared Function IsInSymbolHeader(matchingNode As SyntaxNode, position As Integer) As Boolean
            ' Caret has to be after the attributes if the symbol has any.
            Dim lastAttributes = matchingNode.ChildNodes().LastOrDefault(
                Function(n) TypeOf n Is AttributeListSyntax)
            Dim start = If(lastAttributes?.GetLastToken().GetNextToken().SpanStart,
                           matchingNode.SpanStart)
 
            If position < start Then
                Return False
            End If
 
            Dim asClause = matchingNode.ChildNodes().LastOrDefault(Function(n) TypeOf n Is AsClauseSyntax)
            If asClause IsNot Nothing Then
                Return position <= asClause.FullSpan.End
            End If
 
            ' If the symbol has a parameter list, then the caret shouldn't be past the end of it.
            Dim parameterList = matchingNode.ChildNodes().LastOrDefault(
                Function(n) TypeOf n Is ParameterListSyntax)
            If parameterList IsNot Nothing Then
                Return position <= parameterList.FullSpan.End
            End If
 
            ' Case we haven't handled yet.  Just assume we're in the header.
            Return True
        End Function
 
        Private Shared Function TryGetDeclaredSymbol(semanticModel As SemanticModel,
                                              matchingNode As SyntaxNode,
                                              cancellationToken As CancellationToken) As ISymbol
            Select Case matchingNode.Kind()
                Case SyntaxKind.PropertyBlock
                    Dim parameterList = DirectCast(matchingNode, PropertyBlockSyntax).PropertyStatement.ParameterList
                    Return If(parameterList IsNot Nothing AndAlso parameterList.Parameters.Any(),
                        semanticModel.GetDeclaredSymbol(matchingNode, cancellationToken),
                        Nothing)
                Case SyntaxKind.PropertyStatement
                    Dim parameterList = DirectCast(matchingNode, PropertyStatementSyntax).ParameterList
                    Return If(parameterList IsNot Nothing AndAlso parameterList.Parameters.Any(),
                        semanticModel.GetDeclaredSymbol(matchingNode, cancellationToken),
                        Nothing)
                Case SyntaxKind.SubBlock
                    Return semanticModel.GetDeclaredSymbol(DirectCast(matchingNode, MethodBlockSyntax).BlockStatement, cancellationToken)
                Case SyntaxKind.FunctionBlock
                    Return semanticModel.GetDeclaredSymbol(DirectCast(matchingNode, MethodBlockSyntax).BlockStatement, cancellationToken)
                Case SyntaxKind.ConstructorBlock
                    Return semanticModel.GetDeclaredSymbol(DirectCast(matchingNode, ConstructorBlockSyntax).BlockStatement, cancellationToken)
            End Select
 
            Return semanticModel.GetDeclaredSymbol(matchingNode, cancellationToken)
        End Function
 
        Public Overrides Function FindNodeToUpdate(document As Document, node As SyntaxNode) As SyntaxNode
            Dim vbnode = DirectCast(node, VisualBasicSyntaxNode)
 
            If _updatableNodeKinds.Contains(node.Kind()) Then
                Return GetUpdatableNode(node)
            End If
 
            Dim matchingNode = node.AncestorsAndSelf().FirstOrDefault(Function(a) _updatableAncestorKinds.Contains(a.Kind()))
            If matchingNode Is Nothing Then
                Return Nothing
            End If
 
            Return GetNodeContainingTargetNode(node, matchingNode)
        End Function
 
        Private Shared Function GetNodeContainingTargetNode(originalNode As SyntaxNode, matchingNode As SyntaxNode) As SyntaxNode
            If matchingNode.IsKind(SyntaxKind.InvocationExpression) Then
                Return If(
                    originalNode.AncestorsAndSelf().Any(Function(n) n Is DirectCast(matchingNode, InvocationExpressionSyntax).Expression) OrElse
                        originalNode Is DirectCast(matchingNode, InvocationExpressionSyntax).ArgumentList,
                    GetUpdatableNode(matchingNode),
                    Nothing)
            End If
 
            Dim nodeContainingOriginal = matchingNode
 
            If nodeContainingOriginal.IsKind(SyntaxKind.ObjectCreationExpression) Then
                nodeContainingOriginal = DirectCast(nodeContainingOriginal, ObjectCreationExpressionSyntax).Type
            End If
 
            Return If(originalNode.AncestorsAndSelf().Any(Function(n) n Is nodeContainingOriginal), GetUpdatableNode(matchingNode), Nothing)
 
        End Function
 
        Private Shared Function GetUpdatableNode(matchingNode As SyntaxNode) As SyntaxNode
            If _nodeKindsToIgnore.Contains(matchingNode.Kind()) Then
                Return Nothing
            End If
 
            If matchingNode.IsKind(SyntaxKind.EventStatement) AndAlso matchingNode.IsParentKind(SyntaxKind.EventBlock) Then
                matchingNode = matchingNode.Parent
            End If
 
            Return matchingNode
        End Function
 
        Public Overrides Async Function ChangeSignatureAsync(
            document As Document,
            declarationSymbol As ISymbol,
            potentiallyUpdatedNode As SyntaxNode,
            originalNode As SyntaxNode,
            updatedSignature As SignatureChange,
            cancellationToken As CancellationToken) As Task(Of SyntaxNode)
 
            Dim vbnode = DirectCast(potentiallyUpdatedNode, VisualBasicSyntaxNode)
            If vbnode.IsKind(SyntaxKind.SubStatement) OrElse
               vbnode.IsKind(SyntaxKind.FunctionStatement) OrElse
               vbnode.IsKind(SyntaxKind.SubNewStatement) OrElse
               vbnode.IsKind(SyntaxKind.Attribute) OrElse
               vbnode.IsKind(SyntaxKind.PropertyStatement) OrElse
               vbnode.IsKind(SyntaxKind.DelegateSubStatement) OrElse
               vbnode.IsKind(SyntaxKind.DelegateFunctionStatement) OrElse
               vbnode.IsKind(SyntaxKind.EventBlock) OrElse
               vbnode.IsKind(SyntaxKind.EventStatement) Then
 
                Dim updatedLeadingTrivia = Await UpdateParamNodesInLeadingTriviaAsync(document, vbnode, declarationSymbol, updatedSignature, cancellationToken).ConfigureAwait(False)
                vbnode = vbnode.WithLeadingTrivia(updatedLeadingTrivia)
            End If
 
            If vbnode.IsKind(SyntaxKind.SubStatement) OrElse vbnode.IsKind(SyntaxKind.FunctionStatement) Then
                Dim method = DirectCast(vbnode, MethodStatementSyntax)
                Dim updatedParameters = UpdateDeclaration(method.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                Return method.WithParameterList(method.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
            End If
 
            If vbnode.IsKind(SyntaxKind.EventStatement) Then
                Dim eventStatement = DirectCast(vbnode, EventStatementSyntax)
 
                If eventStatement.ParameterList IsNot Nothing Then
                    Dim updatedParameters = UpdateDeclaration(eventStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                    eventStatement = eventStatement.WithParameterList(eventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
                End If
 
                Return eventStatement
            End If
 
            If vbnode.IsKind(SyntaxKind.EventBlock) Then
                Dim eventBlock = DirectCast(vbnode, EventBlockSyntax)
 
                If eventBlock.EventStatement.ParameterList IsNot Nothing Then
                    Dim updatedParameters = UpdateDeclaration(eventBlock.EventStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                    Return eventBlock.WithEventStatement(eventBlock.EventStatement.WithParameterList(eventBlock.EventStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)))
                End If
 
                Dim raiseEventAccessor = eventBlock.Accessors.FirstOrDefault(Function(a) a.IsKind(SyntaxKind.RaiseEventAccessorBlock))
                If raiseEventAccessor IsNot Nothing Then
                    If raiseEventAccessor.BlockStatement.ParameterList IsNot Nothing Then
                        Dim updatedParameters = UpdateDeclaration(raiseEventAccessor.BlockStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                        Dim updatedRaiseEventAccessor = raiseEventAccessor.WithAccessorStatement(raiseEventAccessor.AccessorStatement.WithParameterList(raiseEventAccessor.AccessorStatement.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation)))
                        eventBlock = eventBlock.WithAccessors(eventBlock.Accessors.Remove(raiseEventAccessor).Add(updatedRaiseEventAccessor))
                    End If
                End If
 
                Return eventBlock
            End If
 
            If vbnode.IsKind(SyntaxKind.RaiseEventStatement) Then
                Dim raiseEventStatement = DirectCast(vbnode, RaiseEventStatementSyntax)
                Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
                Dim delegateInvokeMethod = DirectCast(DirectCast(semanticModel.GetSymbolInfo(raiseEventStatement.Name, cancellationToken).Symbol, IEventSymbol).Type, INamedTypeSymbol).DelegateInvokeMethod
 
                Return raiseEventStatement.WithArgumentList(Await UpdateArgumentListAsync(
                    delegateInvokeMethod,
                    updatedSignature,
                    raiseEventStatement.ArgumentList,
                    isReducedExtensionMethod:=False,
                    isParamsArrayExpanded:=False,
                    generateAttributeArguments:=False,
                    document,
                    originalNode.SpanStart,
                    cancellationToken).ConfigureAwait(False))
            End If
 
            If vbnode.IsKind(SyntaxKind.InvocationExpression) Then
                Dim invocation = DirectCast(vbnode, InvocationExpressionSyntax)
                Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
 
                Dim isReducedExtensionMethod = False
                Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, InvocationExpressionSyntax), cancellationToken)
                Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol)
                If methodSymbol IsNot Nothing AndAlso methodSymbol.MethodKind = MethodKind.ReducedExtension Then
                    isReducedExtensionMethod = True
                End If
 
                If invocation.ArgumentList Is Nothing Then
                    ' If the invocation doesn't contain an argument list, we don't want to add one unless necessary.
                    ' In the case an argument list isn't needed, we can return early as there will be no changes to the invocation.
                    If updatedSignature.UpdatedConfiguration.ParametersWithoutDefaultValues.IsEmpty Then
                        Return invocation
                    Else
                        ' The invocation requires an argument list - add one.
                        Dim emptyArgumentList = SyntaxFactory.ArgumentList().WithTrailingTrivia(invocation.GetTrailingTrivia())
                        invocation = invocation.WithoutTrailingTrivia().WithArgumentList(emptyArgumentList)
                    End If
                End If
 
                Return invocation.WithArgumentList(Await UpdateArgumentListAsync(
                    declarationSymbol,
                    updatedSignature,
                    invocation.ArgumentList,
                    isReducedExtensionMethod,
                    IsParamsArrayExpanded(semanticModel, invocation, symbolInfo, cancellationToken),
                    generateAttributeArguments:=False,
                    document,
                    originalNode.SpanStart,
                    cancellationToken).ConfigureAwait(False))
            End If
 
            If vbnode.IsKind(SyntaxKind.SubNewStatement) Then
                Dim constructor = DirectCast(vbnode, SubNewStatementSyntax)
                Dim newParameters = UpdateDeclaration(constructor.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                Return constructor.WithParameterList(constructor.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
            End If
 
            If vbnode.IsKind(SyntaxKind.Attribute) Then
                Dim attribute = DirectCast(vbnode, AttributeSyntax)
 
                Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
                Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, AttributeSyntax), cancellationToken)
                Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol)
 
                Return attribute.WithArgumentList(Await UpdateArgumentListAsync(
                    declarationSymbol,
                    updatedSignature,
                    attribute.ArgumentList,
                    isReducedExtensionMethod:=False,
                    isParamsArrayExpanded:=False,
                    generateAttributeArguments:=True,
                    document,
                    originalNode.SpanStart,
                    cancellationToken).ConfigureAwait(False))
            End If
 
            If vbnode.IsKind(SyntaxKind.ObjectCreationExpression) Then
                Dim objectCreation = DirectCast(vbnode, ObjectCreationExpressionSyntax)
                Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
 
                Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, ObjectCreationExpressionSyntax), cancellationToken)
                Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol)
 
                Dim paramsArrayExpanded = IsParamsArrayExpanded(semanticModel, objectCreation, symbolInfo, cancellationToken)
 
                Return objectCreation.WithArgumentList(Await UpdateArgumentListAsync(
                    declarationSymbol,
                    updatedSignature,
                    objectCreation.ArgumentList,
                    isReducedExtensionMethod:=False,
                    IsParamsArrayExpanded(semanticModel, objectCreation, symbolInfo, cancellationToken),
                    generateAttributeArguments:=False,
                    document,
                    originalNode.SpanStart,
                    cancellationToken).ConfigureAwait(False))
            End If
 
            If vbnode.IsKind(SyntaxKind.PropertyStatement) Then
                Dim propertyStatement = DirectCast(vbnode, PropertyStatementSyntax)
                Dim newParameters = UpdateDeclaration(propertyStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                Return propertyStatement.WithParameterList(propertyStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
            End If
 
            If vbnode.IsKind(SyntaxKind.CrefReference) Then
                Dim crefReference = DirectCast(vbnode, CrefReferenceSyntax)
 
                If crefReference.Signature Is Nothing OrElse
                   Not crefReference.Signature.ArgumentTypes.Any() Then
                    Return crefReference
                End If
 
                Dim newParameters = UpdateDeclaration(crefReference.Signature.ArgumentTypes, updatedSignature, s_createNewCrefParameterSyntaxDelegate)
                Return crefReference.WithSignature(crefReference.Signature.WithArgumentTypes(newParameters))
            End If
 
            If vbnode.IsKind(SyntaxKind.SingleLineSubLambdaExpression) OrElse
               vbnode.IsKind(SyntaxKind.SingleLineFunctionLambdaExpression) Then
 
                Dim lambda = DirectCast(vbnode, SingleLineLambdaExpressionSyntax)
 
                If Not lambda.SubOrFunctionHeader.ParameterList.Parameters.Any() Then
                    Return vbnode
                End If
 
                Dim newParameters = UpdateDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
                Return lambda.WithSubOrFunctionHeader(newBegin)
            End If
 
            If vbnode.IsKind(SyntaxKind.MultiLineSubLambdaExpression) OrElse
               vbnode.IsKind(SyntaxKind.MultiLineFunctionLambdaExpression) Then
 
                Dim lambda = DirectCast(vbnode, MultiLineLambdaExpressionSyntax)
 
                If Not lambda.SubOrFunctionHeader.ParameterList.Parameters.Any() Then
                    Return vbnode
                End If
 
                Dim newParameters = UpdateDeclaration(lambda.SubOrFunctionHeader.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                Dim newBegin = lambda.SubOrFunctionHeader.WithParameterList(lambda.SubOrFunctionHeader.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
                Return lambda.WithSubOrFunctionHeader(newBegin)
            End If
 
            If vbnode.IsKind(SyntaxKind.DelegateSubStatement) OrElse
               vbnode.IsKind(SyntaxKind.DelegateFunctionStatement) Then
                Dim delegateStatement = DirectCast(vbnode, DelegateStatementSyntax)
                Dim newParameters = UpdateDeclaration(delegateStatement.ParameterList.Parameters, updatedSignature, s_createNewParameterSyntaxDelegate)
                Return delegateStatement.WithParameterList(delegateStatement.ParameterList.WithParameters(newParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation))
            End If
 
            Return vbnode
        End Function
 
        Private Async Function UpdateArgumentListAsync(
            declarationSymbol As ISymbol,
            signaturePermutation As SignatureChange,
            argumentList As ArgumentListSyntax,
            isReducedExtensionMethod As Boolean,
            isParamsArrayExpanded As Boolean,
            generateAttributeArguments As Boolean,
            document As Document,
            position As Integer,
            cancellationToken As CancellationToken) As Task(Of ArgumentListSyntax)
 
            Dim newArguments = PermuteArgumentList(
                argumentList.Arguments,
                signaturePermutation.WithoutAddedParameters(),
                declarationSymbol,
                isReducedExtensionMethod)
 
            newArguments = Await AddNewArgumentsToListAsync(
                declarationSymbol,
                newArguments,
                signaturePermutation,
                isReducedExtensionMethod,
                isParamsArrayExpanded,
                generateAttributeArguments,
                document,
                position,
                cancellationToken).ConfigureAwait(False)
 
            Return argumentList.
                WithArguments(newArguments).
                WithAdditionalAnnotations(changeSignatureFormattingAnnotation)
        End Function
 
        Private Shared Function IsParamsArrayExpanded(semanticModel As SemanticModel, node As SyntaxNode, symbolInfo As SymbolInfo, cancellationToken As CancellationToken) As Boolean
            If symbolInfo.Symbol Is Nothing Then
                Return False
            End If
 
            Dim argumentCount As Integer
            Dim lastArgumentIsNamed As Boolean
            Dim lastArgumentExpression As ExpressionSyntax = Nothing
 
            Dim invocation = TryCast(node, InvocationExpressionSyntax)
            Dim objectCreation = TryCast(node, ObjectCreationExpressionSyntax)
            If invocation IsNot Nothing Then
                GetArgumentListDetailsRegardingParamsArrays(invocation.ArgumentList, argumentCount, lastArgumentIsNamed, lastArgumentExpression)
            ElseIf objectCreation IsNot Nothing Then
                GetArgumentListDetailsRegardingParamsArrays(objectCreation.ArgumentList, argumentCount, lastArgumentIsNamed, lastArgumentExpression)
            Else
                Throw ExceptionUtilities.UnexpectedValue(node.Kind())
            End If
 
            Return IsParamsArrayExpandedHelper(symbolInfo.Symbol, argumentCount, lastArgumentIsNamed, semanticModel, lastArgumentExpression, cancellationToken)
        End Function
 
        Private Shared Sub GetArgumentListDetailsRegardingParamsArrays(
            argumentList As ArgumentListSyntax,
            ByRef argumentCount As Integer,
            ByRef lastArgumentIsNamed As Boolean,
            ByRef lastArgumentExpression As ExpressionSyntax)
 
            argumentCount = argumentList.Arguments.Count
            Dim isNamed = argumentList.Arguments.LastOrDefault()?.IsNamed
            lastArgumentIsNamed = isNamed.GetValueOrDefault()
            lastArgumentExpression = argumentList.Arguments.LastOrDefault()?.GetExpression()
        End Sub
 
        Private Function PermuteArgumentList(
            arguments As SeparatedSyntaxList(Of ArgumentSyntax),
            permutedSignature As SignatureChange,
            declarationSymbol As ISymbol,
            Optional isReducedExtensionMethod As Boolean = False) As SeparatedSyntaxList(Of ArgumentSyntax)
 
            Dim newArguments As ImmutableArray(Of IUnifiedArgumentSyntax) = PermuteArguments(
                declarationSymbol, arguments.Select(Function(a) UnifiedArgumentSyntax.Create(a)).ToImmutableArray(), permutedSignature,
                isReducedExtensionMethod)
 
            Dim numSeparatorsToSkip As Integer
            If arguments.Count = 0 Then
                ' () 
                ' Adding X parameters, need to add X-1 separators.
                numSeparatorsToSkip = arguments.Count - newArguments.Length + 1
            Else
                ' (a,b,c)
                ' Adding X parameters, need to add X separators.
                numSeparatorsToSkip = arguments.Count - newArguments.Length
            End If
 
            Return SeparatedList(newArguments.Select(Function(a) CType(DirectCast(a, UnifiedArgumentSyntax), ArgumentSyntax)), GetSeparators(arguments, numSeparatorsToSkip))
        End Function
 
        Private Function UpdateDeclaration(Of T As SyntaxNode)(
                parameterList As SeparatedSyntaxList(Of T),
                updatedSignature As SignatureChange,
                createNewParameterMethod As Func(Of AddedParameter, T)) As SeparatedSyntaxList(Of T)
            Dim updatedDeclaration = UpdateDeclarationBase(parameterList, updatedSignature, createNewParameterMethod)
            Return SeparatedList(updatedDeclaration.parameters, updatedDeclaration.separators)
        End Function
 
        Private Shared Function CreateNewParameterSyntax(addedParameter As AddedParameter) As ParameterSyntax
            Return SyntaxFactory.Parameter(
                attributeLists:=New SyntaxList(Of AttributeListSyntax)(),
                modifiers:=If(addedParameter.HasDefaultValue, TokenList(Token(SyntaxKind.OptionalKeyword)), TokenList()),
                identifier:=ModifiedIdentifier(addedParameter.Name),
                asClause:=SimpleAsClause(
                    addedParameter.Type.GenerateTypeSyntax() _
                    .WithPrependedLeadingTrivia(ElasticSpace)) _
                    .WithPrependedLeadingTrivia(ElasticSpace),
                [default]:=If(addedParameter.HasDefaultValue, EqualsValue(ParseExpression(addedParameter.DefaultValue)), Nothing))
        End Function
 
        Private Shared Function CreateNewCrefParameterSyntax(addedParameter As AddedParameter) As CrefSignaturePartSyntax
            Return CrefSignaturePart(
                modifier:=Nothing,
                type:=addedParameter.Type.GenerateTypeSyntax())
        End Function
 
        Private Async Function UpdateParamNodesInLeadingTriviaAsync(
            document As Document,
            node As VisualBasicSyntaxNode,
            declarationSymbol As ISymbol,
            updatedSignature As SignatureChange,
            cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of SyntaxTrivia))
 
            If Not node.HasLeadingTrivia Then
                Return ImmutableArray(Of SyntaxTrivia).Empty
            End If
 
            Dim paramNodes = node _
                .DescendantNodes(descendIntoTrivia:=True) _
                .OfType(Of XmlElementSyntax)() _
                .Where(Function(e) e.StartTag.Name.ToString() = DocumentationCommentXmlNames.ParameterElementName) _
                .ToImmutableArray()
 
            Dim permutedParamNodes = VerifyAndPermuteParamNodes(paramNodes, declarationSymbol, updatedSignature)
            If permutedParamNodes.IsEmpty() Then
                ' Something is wrong with the <param> tags, so don't change anything.
                Return node.GetLeadingTrivia().ToImmutableArray()
            End If
 
            Dim options = Await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(False)
            Return GetPermutedDocCommentTrivia(node, permutedParamNodes, document.Project.Services, options)
        End Function
 
        Private Function VerifyAndPermuteParamNodes(paramNodes As ImmutableArray(Of XmlElementSyntax), declarationSymbol As ISymbol, updatedSignature As SignatureChange) As ImmutableArray(Of SyntaxNode)
            ' Only reorder if count and order match originally.
 
            Dim originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters()
            Dim reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters()
 
            Dim declaredParameters = GetParameters(declarationSymbol)
            If paramNodes.Length <> declaredParameters.Length Then
                Return ImmutableArray(Of SyntaxNode).Empty
            End If
 
            If declaredParameters.Length = 0 Then
                Return ImmutableArray(Of SyntaxNode).Empty
            End If
 
            Dim dictionary = New Dictionary(Of String, XmlElementSyntax)()
            Dim i = 0
            For Each paramNode In paramNodes
                Dim nameAttribute = paramNode.StartTag.Attributes.OfType(Of XmlNameAttributeSyntax).FirstOrDefault(Function(a) a.Name.ToString() = "name")
                If nameAttribute Is Nothing Then
                    Return ImmutableArray(Of SyntaxNode).Empty
                End If
 
                Dim identifier = nameAttribute.DescendantNodes(descendIntoTrivia:=True).OfType(Of IdentifierNameSyntax)().FirstOrDefault()
                If (identifier Is Nothing OrElse identifier.ToString() <> declaredParameters.ElementAt(i).Name) Then
                    Return ImmutableArray(Of SyntaxNode).Empty
                End If
 
                dictionary.Add(originalParameters(i).Name.ToString(), paramNode)
                i += 1
            Next
 
            ' Everything lines up, so permute them.
            Dim permutedParams = ArrayBuilder(Of SyntaxNode).GetInstance()
            For Each parameter In reorderedParameters
                Dim permutedParam As XmlElementSyntax = Nothing
                If dictionary.TryGetValue(parameter.Name, permutedParam) Then
                    permutedParams.Add(permutedParam)
                Else
                    permutedParams.Add(XmlElement(
                        XmlElementStartTag(
                            XmlName(Nothing, XmlNameToken(DocumentationCommentXmlNames.ParameterElementName, SyntaxKind.XmlNameToken)),
                            List(Of XmlNodeSyntax)({XmlNameAttribute(parameter.Name)})),
                        XmlElementEndTag(XmlName(Nothing, XmlNameToken(DocumentationCommentXmlNames.ParameterElementName, SyntaxKind.XmlNameToken)))))
                End If
            Next
 
            Return permutedParams.ToImmutableAndFree()
        End Function
 
        Public Overrides Async Function DetermineCascadedSymbolsFromDelegateInvokeAsync(
                method As IMethodSymbol,
                document As Document,
                cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of ISymbol))
 
            Dim symbol = method
            Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
            Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
 
            Dim nodes = root.DescendantNodes()
 
            Dim results = ArrayBuilder(Of ISymbol).GetInstance()
 
            For Each n In nodes
                If n.IsKind(SyntaxKind.AddressOfExpression) Then
                    Dim u = DirectCast(n, UnaryExpressionSyntax)
                    Dim convertedType As ISymbol = semanticModel.GetTypeInfo(u, cancellationToken).ConvertedType
                    If convertedType IsNot Nothing Then
                        convertedType = convertedType.OriginalDefinition
                    End If
 
                    If convertedType IsNot Nothing Then
                        convertedType = If(Await SymbolFinder.FindSourceDefinitionAsync(convertedType, document.Project.Solution, cancellationToken).ConfigureAwait(False), convertedType)
                    End If
 
                    If Equals(convertedType, symbol.ContainingType) Then
                        convertedType = semanticModel.GetSymbolInfo(u.Operand, cancellationToken).Symbol
                        If convertedType IsNot Nothing Then
                            results.Add(convertedType)
                        End If
                    End If
                ElseIf n.IsKind(SyntaxKind.EventStatement) Then
                    Dim cast = DirectCast(n, EventStatementSyntax)
                    If cast.AsClause IsNot Nothing Then
                        Dim nodeType = semanticModel.GetSymbolInfo(cast.AsClause.Type, cancellationToken).Symbol
 
                        If nodeType IsNot Nothing Then
                            nodeType = nodeType.OriginalDefinition
                        End If
 
                        If nodeType IsNot Nothing Then
                            nodeType = If(Await SymbolFinder.FindSourceDefinitionAsync(nodeType, document.Project.Solution, cancellationToken).ConfigureAwait(False), nodeType)
                        End If
 
                        If Equals(nodeType, symbol.ContainingType) Then
                            results.Add(semanticModel.GetDeclaredSymbol(cast.Identifier.Parent, cancellationToken))
                        End If
                    End If
                End If
            Next
 
            Return results.ToImmutableAndFree()
        End Function
 
        Protected Overrides Function GetFormattingRules(document As Document) As ImmutableArray(Of AbstractFormattingRule)
            Dim coreRules = Formatter.GetDefaultFormattingRules(document)
            Dim result = New FixedSizeArrayBuilder(Of AbstractFormattingRule)(1 + coreRules.Length)
            result.Add(New ChangeSignatureFormattingRule())
            result.AddRange(coreRules)
            Return result.MoveToImmutable()
        End Function
 
        Protected Overrides Function TransferLeadingWhitespaceTrivia(Of T As SyntaxNode)(newArgument As T, oldArgument As SyntaxNode) As T
            Return newArgument
        End Function
 
        Protected Overrides ReadOnly Property Generator As SyntaxGenerator
            Get
                Return VisualBasicSyntaxGenerator.Instance
            End Get
        End Property
 
        Protected Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts
            Get
                Return VisualBasicSyntaxFacts.Instance
            End Get
        End Property
 
        Protected Overrides Function CreateExplicitParamsArrayFromIndividualArguments(Of TArgumentSyntax As SyntaxNode)(newArguments As SeparatedSyntaxList(Of TArgumentSyntax), indexInExistingList As Integer, parameterSymbol As IParameterSymbol) As TArgumentSyntax
            ' A params array cannot be introduced due to the addition of an omitted 
            ' argument in VB because you cannot have a named argument to a params array.
            Throw New InvalidOperationException()
        End Function
 
        Protected Overrides Function AddNameToArgument(Of TArgumentSyntax As SyntaxNode)(newArgument As TArgumentSyntax, name As String) As TArgumentSyntax
            Dim simpleArgument = TryCast(newArgument, SimpleArgumentSyntax)
            If simpleArgument IsNot Nothing Then
                Return CType(CType(simpleArgument.WithNameColonEquals(NameColonEquals(IdentifierName(name))), SyntaxNode), TArgumentSyntax)
            End If
 
            Dim omittedArgument = TryCast(newArgument, OmittedArgumentSyntax)
            If omittedArgument IsNot Nothing Then
                Return CType(CType(omittedArgument, SyntaxNode), TArgumentSyntax)
            End If
 
            Throw ExceptionUtilities.UnexpectedValue(newArgument.Kind())
        End Function
 
        Protected Overrides Function SupportsOptionalAndParamsArrayParametersSimultaneously() As Boolean
            Return False
        End Function
 
        Protected Overrides Function CommaTokenWithElasticSpace() As SyntaxToken
            Return Token(SyntaxKind.CommaToken).WithTrailingTrivia(ElasticSpace)
        End Function
 
        Protected Overrides Function TryGetRecordPrimaryConstructor(typeSymbol As INamedTypeSymbol, ByRef primaryConstructor As IMethodSymbol) As Boolean
            Return False
        End Function
 
        Protected Overrides Function GetParameters(declarationSymbol As ISymbol) As ImmutableArray(Of IParameterSymbol)
            Return declarationSymbol.GetParameters()
        End Function
    End Class
End Namespace