File: src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\CodeGeneration\VisualBasicCodeGenerationService.vb
Web Access
Project: src\src\Workspaces\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj (Microsoft.CodeAnalysis.VisualBasic.Workspaces)
' 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.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.CodeGeneration
Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.LanguageService
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
    Friend NotInheritable Class VisualBasicCodeGenerationService
        Inherits AbstractCodeGenerationService(Of VisualBasicCodeGenerationContextInfo)
 
        Public Sub New(languageServices As LanguageServices)
            MyBase.New(languageServices)
        End Sub
 
        Public Overrides ReadOnly Property DefaultOptions As CodeGenerationOptions
            Get
                Return VisualBasicCodeGenerationOptions.Default
            End Get
        End Property
 
        Public Overrides Function GetCodeGenerationOptions(options As IOptionsReader) As CodeGenerationOptions
            Return New VisualBasicCodeGenerationOptions(options)
        End Function
 
        Public Overrides Function GetInfo(context As CodeGenerationContext, options As CodeGenerationOptions, parseOptions As ParseOptions) As VisualBasicCodeGenerationContextInfo
            Return New VisualBasicCodeGenerationContextInfo(context, DirectCast(options, VisualBasicCodeGenerationOptions), Me)
        End Function
 
        Public Overloads Overrides Function GetDestination(containerNode As SyntaxNode) As CodeGenerationDestination
            Return VisualBasicCodeGenerationHelpers.GetDestination(containerNode)
        End Function
 
        Protected Overrides Function GetMemberComparer() As IComparer(Of SyntaxNode)
            Return VisualBasicDeclarationComparer.WithoutNamesInstance
        End Function
 
        Protected Overrides Function GetAvailableInsertionIndices(destination As SyntaxNode, cancellationToken As CancellationToken) As IList(Of Boolean)
            ' NOTE(cyrusn): We know that the destination overlaps some hidden regions.
            If TypeOf destination Is TypeBlockSyntax Then
                Return DirectCast(destination, TypeBlockSyntax).GetInsertionIndices(cancellationToken)
            End If
 
            If TypeOf destination Is CompilationUnitSyntax Then
                Return GetAvailableInsertionIndices(DirectCast(destination, CompilationUnitSyntax), cancellationToken)
            End If
 
            ' TODO(cyrusn): This will exclude all non-type-blocks if they overlap a hidden region.
            ' For example, for enums or namespaces.  We could consider relaxing that and actually
            ' attempting to determine where in the destination are viable, if we think it's worth
            ' it.
            Return Nothing
        End Function
 
        Private Overloads Shared Function GetAvailableInsertionIndices(destination As CompilationUnitSyntax, cancellationToken As CancellationToken) As IList(Of Boolean)
            Dim members = destination.Members
 
            Dim indices = New List(Of Boolean)
            If members.Count >= 1 Then
                ' First, see if we can insert between the start of the typeblock, and it's first
                ' member.
                indices.Add(Not destination.OverlapsHiddenPosition(TextSpan.FromBounds(0, destination.Members.First.SpanStart), cancellationToken))
 
                ' Now, walk between each member and see if something can be inserted between it and
                ' the next member
                For i = 0 To members.Count - 2
                    Dim member1 = members(i)
                    Dim member2 = members(i + 1)
 
                    indices.Add(Not destination.OverlapsHiddenPosition(member1, member2, cancellationToken))
                Next
 
                ' Last, see if we can insert between the last member and the end of the typeblock
                indices.Add(Not destination.OverlapsHiddenPosition(
                    TextSpan.FromBounds(destination.Members.Last.Span.End, destination.EndOfFileToken.SpanStart), cancellationToken))
            End If
 
            Return indices
        End Function
 
        Protected Overrides Function AddEvent(Of TDeclarationNode As SyntaxNode)(
                destinationType As TDeclarationNode,
                [event] As IEventSymbol,
                options As VisualBasicCodeGenerationContextInfo,
                availableIndices As IList(Of Boolean),
                cancellationToken As CancellationToken) As TDeclarationNode
            CheckDeclarationNode(Of TypeBlockSyntax)(destinationType)
            Return Cast(Of TDeclarationNode)(AddEventTo(Cast(Of TypeBlockSyntax)(destinationType), [event], options, availableIndices))
        End Function
 
        Protected Overrides Function AddField(Of TDeclarationNode As SyntaxNode)(
                destinationType As TDeclarationNode,
                field As IFieldSymbol,
                options As VisualBasicCodeGenerationContextInfo,
                availableIndices As IList(Of Boolean),
                cancellationToken As CancellationToken) As TDeclarationNode
            CheckDeclarationNode(Of EnumBlockSyntax, TypeBlockSyntax, CompilationUnitSyntax)(destinationType)
            If TypeOf destinationType Is EnumBlockSyntax Then
                Return Cast(Of TDeclarationNode)(EnumMemberGenerator.AddEnumMemberTo(Cast(Of EnumBlockSyntax)(destinationType), field, options))
            ElseIf TypeOf destinationType Is TypeBlockSyntax Then
                Return Cast(Of TDeclarationNode)(FieldGenerator.AddFieldTo(Cast(Of TypeBlockSyntax)(destinationType), field, options, availableIndices))
            Else
                Return Cast(Of TDeclarationNode)(FieldGenerator.AddFieldTo(Cast(Of CompilationUnitSyntax)(destinationType), field, options, availableIndices))
            End If
        End Function
 
        Protected Overrides Function AddProperty(Of TDeclarationNode As SyntaxNode)(
                destinationType As TDeclarationNode,
                [property] As IPropertySymbol,
                options As VisualBasicCodeGenerationContextInfo,
                availableIndices As IList(Of Boolean),
                cancellationToken As CancellationToken) As TDeclarationNode
            CheckDeclarationNode(Of TypeBlockSyntax, CompilationUnitSyntax)(destinationType)
 
            If TypeOf destinationType Is TypeBlockSyntax Then
                Return Cast(Of TDeclarationNode)(PropertyGenerator.AddPropertyTo(Cast(Of TypeBlockSyntax)(destinationType), [property], options, availableIndices))
            Else
                Return Cast(Of TDeclarationNode)(PropertyGenerator.AddPropertyTo(Cast(Of CompilationUnitSyntax)(destinationType), [property], options, availableIndices))
            End If
        End Function
 
        Protected Overrides Function AddMethod(Of TDeclarationNode As SyntaxNode)(
                destination As TDeclarationNode,
                method As IMethodSymbol,
                options As VisualBasicCodeGenerationContextInfo,
                availableIndices As IList(Of Boolean),
                cancellationToken As CancellationToken) As TDeclarationNode
            CheckDeclarationNode(Of TypeBlockSyntax, CompilationUnitSyntax, NamespaceBlockSyntax)(destination)
 
            ' Synthesized methods for properties/events are not things we actually generate 
            ' declarations for.
            If method.AssociatedSymbol IsNot Nothing Then
                Return destination
            End If
 
            Dim typeDeclaration As TypeBlockSyntax = TryCast(destination, TypeBlockSyntax)
            If typeDeclaration IsNot Nothing Then
                If method.IsConstructor() Then
                    Return Cast(Of TDeclarationNode)(ConstructorGenerator.AddConstructorTo(typeDeclaration, method, options, availableIndices))
                End If
 
                If method.MethodKind = MethodKind.UserDefinedOperator Then
                    Return Cast(Of TDeclarationNode)(OperatorGenerator.AddOperatorTo(typeDeclaration, method, options, availableIndices))
                End If
 
                If method.MethodKind = MethodKind.Conversion Then
                    Return Cast(Of TDeclarationNode)(ConversionGenerator.AddConversionTo(typeDeclaration, method, options, availableIndices))
                End If
 
                Return Cast(Of TDeclarationNode)(MethodGenerator.AddMethodTo(typeDeclaration, method, options, availableIndices))
            End If
 
            If method.IsConstructor() Then
                Return destination
            End If
 
            Dim compilationUnit = TryCast(destination, CompilationUnitSyntax)
            If compilationUnit IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(MethodGenerator.AddMethodTo(compilationUnit, method, options, availableIndices))
            End If
 
            Dim ns = Cast(Of NamespaceBlockSyntax)(destination)
            Return Cast(Of TDeclarationNode)(MethodGenerator.AddMethodTo(ns, method, options, availableIndices))
        End Function
 
        Protected Overloads Overrides Function AddNamedType(Of TDeclarationNode As SyntaxNode)(
                destination As TDeclarationNode,
                namedType As INamedTypeSymbol,
                options As VisualBasicCodeGenerationContextInfo,
                availableIndices As IList(Of Boolean),
                cancellationToken As CancellationToken) As TDeclarationNode
            CheckDeclarationNode(Of TypeBlockSyntax, NamespaceBlockSyntax, CompilationUnitSyntax)(destination)
            If TypeOf destination Is TypeBlockSyntax Then
                Return Cast(Of TDeclarationNode)(NamedTypeGenerator.AddNamedTypeTo(Me, Cast(Of TypeBlockSyntax)(destination), namedType, options, availableIndices, cancellationToken))
            ElseIf TypeOf destination Is NamespaceBlockSyntax Then
                Return Cast(Of TDeclarationNode)(NamedTypeGenerator.AddNamedTypeTo(Me, Cast(Of NamespaceBlockSyntax)(destination), namedType, options, availableIndices, cancellationToken))
            Else
                Return Cast(Of TDeclarationNode)(NamedTypeGenerator.AddNamedTypeTo(Me, Cast(Of CompilationUnitSyntax)(destination), namedType, options, availableIndices, cancellationToken))
            End If
        End Function
 
        Protected Overrides Function AddNamespace(Of TDeclarationNode As SyntaxNode)(
                destination As TDeclarationNode,
                [namespace] As INamespaceSymbol,
                options As VisualBasicCodeGenerationContextInfo,
                availableIndices As IList(Of Boolean),
                cancellationToken As CancellationToken) As TDeclarationNode
            CheckDeclarationNode(Of CompilationUnitSyntax, NamespaceBlockSyntax)(destination)
 
            If TypeOf destination Is CompilationUnitSyntax Then
                Return Cast(Of TDeclarationNode)(NamespaceGenerator.AddNamespaceTo(Me, Cast(Of CompilationUnitSyntax)(destination), [namespace], options, availableIndices, cancellationToken))
            Else
                Return Cast(Of TDeclarationNode)(NamespaceGenerator.AddNamespaceTo(Me, Cast(Of NamespaceBlockSyntax)(destination), [namespace], options, availableIndices, cancellationToken))
            End If
        End Function
 
        Public Overrides Function AddParameters(Of TDeclarationNode As SyntaxNode)(
                destinationMember As TDeclarationNode,
                parameters As IEnumerable(Of IParameterSymbol),
                options As VisualBasicCodeGenerationContextInfo,
                cancellationToken As CancellationToken) As TDeclarationNode
            Dim methodBlock = TryCast(destinationMember, MethodBlockBaseSyntax)
            Dim methodStatement = If(methodBlock IsNot Nothing,
                                     methodBlock.BlockStatement,
                                     TryCast(destinationMember, MethodBaseSyntax))
 
            If methodStatement IsNot Nothing Then
                Select Case methodStatement.Kind
                    Case SyntaxKind.GetAccessorStatement, SyntaxKind.SetAccessorStatement
                        ' Don't allow adding parameters to Property Getter/Setter
                        Return destinationMember
                    Case Else
                        Return AddParametersToMethod(Of TDeclarationNode)(methodStatement, methodBlock, parameters, options, cancellationToken)
                End Select
            Else
                Dim propertyBlock = TryCast(destinationMember, PropertyBlockSyntax)
                If propertyBlock IsNot Nothing Then
                    Return AddParametersToProperty(Of TDeclarationNode)(propertyBlock, parameters, options, cancellationToken)
                End If
            End If
 
            Return destinationMember
        End Function
 
        Protected Overrides Function AddMembers(Of TDeclarationNode As SyntaxNode)(destination As TDeclarationNode, members As IEnumerable(Of SyntaxNode)) As TDeclarationNode
            CheckDeclarationNode(Of EnumBlockSyntax, TypeBlockSyntax, NamespaceBlockSyntax, CompilationUnitSyntax)(destination)
            If TypeOf destination Is EnumBlockSyntax Then
                Return Cast(Of TDeclarationNode)(Cast(Of EnumBlockSyntax)(destination).AddMembers(members.Cast(Of EnumMemberDeclarationSyntax).ToArray()))
            ElseIf TypeOf destination Is TypeBlockSyntax Then
                Return Cast(Of TDeclarationNode)(Cast(Of TypeBlockSyntax)(destination).AddMembers(members.Cast(Of StatementSyntax).ToArray()))
            ElseIf TypeOf destination Is NamespaceBlockSyntax Then
                Return Cast(Of TDeclarationNode)(Cast(Of NamespaceBlockSyntax)(destination).AddMembers(members.Cast(Of StatementSyntax).ToArray()))
            Else
                Return Cast(Of TDeclarationNode)(Cast(Of CompilationUnitSyntax)(destination).AddMembers(members.Cast(Of StatementSyntax).ToArray()))
            End If
        End Function
 
        Private Overloads Function AddParametersToMethod(Of TDeclarationNode As SyntaxNode)(
                methodStatement As MethodBaseSyntax,
                methodBlock As MethodBlockBaseSyntax,
                parameters As IEnumerable(Of IParameterSymbol),
                options As VisualBasicCodeGenerationContextInfo,
                cancellationToken As CancellationToken) As TDeclarationNode
            Dim finalStatement = AddParameterToMethodBase(methodStatement, parameters, options, cancellationToken)
 
            Dim result As StatementSyntax
            If methodBlock IsNot Nothing Then
                Select Case methodBlock.Kind
                    Case SyntaxKind.SubBlock,
                        SyntaxKind.FunctionBlock
                        result = DirectCast(methodBlock, MethodBlockSyntax).WithBlockStatement(DirectCast(finalStatement, MethodStatementSyntax))
 
                    Case SyntaxKind.ConstructorBlock
                        result = DirectCast(methodBlock, ConstructorBlockSyntax).WithBlockStatement(DirectCast(finalStatement, SubNewStatementSyntax))
 
                    Case SyntaxKind.GetAccessorBlock,
                        SyntaxKind.SetAccessorBlock,
                        SyntaxKind.AddHandlerAccessorBlock,
                        SyntaxKind.RemoveHandlerAccessorBlock,
                        SyntaxKind.RaiseEventAccessorBlock
                        result = DirectCast(methodBlock, AccessorBlockSyntax).WithBlockStatement(DirectCast(finalStatement, AccessorStatementSyntax))
 
                    Case Else
                        result = DirectCast(methodBlock, OperatorBlockSyntax).WithBlockStatement(DirectCast(finalStatement, OperatorStatementSyntax))
                End Select
            Else
                result = finalStatement
            End If
 
            Return DirectCast(DirectCast(result, Object), TDeclarationNode)
        End Function
 
        Private Overloads Function AddParametersToProperty(Of TDeclarationNode As SyntaxNode)(
                propertyBlock As PropertyBlockSyntax,
                parameters As IEnumerable(Of IParameterSymbol),
                options As VisualBasicCodeGenerationContextInfo,
                cancellationToken As CancellationToken) As TDeclarationNode
            Dim propertyStatement = propertyBlock.PropertyStatement
            Dim newPropertyStatement = AddParameterToMethodBase(propertyStatement, parameters, options, cancellationToken)
            Dim newPropertyBlock As SyntaxNode = propertyBlock.WithPropertyStatement(newPropertyStatement)
            Return DirectCast(newPropertyBlock, TDeclarationNode)
        End Function
 
        Private Overloads Function AddParameterToMethodBase(Of TMethodBase As MethodBaseSyntax)(
                methodBase As TMethodBase,
                parameters As IEnumerable(Of IParameterSymbol),
                options As VisualBasicCodeGenerationContextInfo,
                cancellationToken As CancellationToken) As TMethodBase
 
            Dim parameterList = methodBase.ParameterList
 
            Dim parameterCount = If(parameterList IsNot Nothing, parameterList.Parameters.Count, 0)
            Dim seenOptional = parameterCount > 0 AndAlso parameterList.Parameters(parameterCount - 1).Default IsNot Nothing
 
            Dim editor = New SyntaxEditor(methodBase, Me.LanguageServices.SolutionServices)
            For Each parameter In parameters
                Dim parameterSyntax = ParameterGenerator.GenerateParameter(parameter, seenOptional, options)
 
                AddParameterEditor.AddParameter(
                    VisualBasicSyntaxFacts.Instance,
                    editor,
                    methodBase,
                    parameterCount,
                    parameterSyntax,
                    cancellationToken)
 
                seenOptional = seenOptional OrElse parameterSyntax.Default IsNot Nothing
                parameterCount += 1
            Next
 
            Return DirectCast(editor.GetChangedRoot(), TMethodBase)
        End Function
 
        Public Overrides Function AddAttributes(Of TDeclarationNode As SyntaxNode)(
                    destination As TDeclarationNode,
                    attributes As IEnumerable(Of AttributeData),
                    target As SyntaxToken?,
                    options As VisualBasicCodeGenerationContextInfo,
                    cancellationToken As CancellationToken) As TDeclarationNode
 
            If target.HasValue AndAlso Not target.Value.IsValidAttributeTarget() Then
                Throw New ArgumentException(NameOf(target))
            End If
 
            Dim attributeSyntaxList = AttributeGenerator.GenerateAttributeBlocks(attributes.ToImmutableArray(), options, target)
 
            ' Handle most cases
            Dim member = TryCast(destination, StatementSyntax)
            If member IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(member.AddAttributeLists(attributeSyntaxList.ToArray()))
            End If
 
            ' Handle global attributes
            Dim compilationUnit = TryCast(destination, CompilationUnitSyntax)
            If compilationUnit IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(compilationUnit.AddAttributes(SyntaxFactory.AttributesStatement(attributeSyntaxList)))
            End If
 
            ' Handle parameters
            Dim parameter = TryCast(destination, ParameterSyntax)
            If parameter IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(parameter.AddAttributeLists(attributeSyntaxList.ToArray()))
            End If
 
            Return destination
        End Function
 
        Public Overrides Function RemoveAttribute(Of TDeclarationNode As SyntaxNode)(destination As TDeclarationNode, attributeToRemove As AttributeData, options As VisualBasicCodeGenerationContextInfo, cancellationToken As CancellationToken) As TDeclarationNode
            If attributeToRemove.ApplicationSyntaxReference Is Nothing Then
                Throw New ArgumentException(NameOf(attributeToRemove))
            End If
 
            Dim attributeSyntaxToRemove = attributeToRemove.ApplicationSyntaxReference.GetSyntax(cancellationToken)
            Return RemoveAttribute(destination, attributeSyntaxToRemove, options, cancellationToken)
        End Function
 
        Public Overrides Function RemoveAttribute(Of TDeclarationNode As SyntaxNode)(destination As TDeclarationNode, attributeToRemove As SyntaxNode, options As VisualBasicCodeGenerationContextInfo, cancellationToken As CancellationToken) As TDeclarationNode
            If attributeToRemove Is Nothing Then
                Throw New ArgumentException(NameOf(attributeToRemove))
            End If
 
            ' Removed node could be AttributeSyntax or AttributeListSyntax.
            Dim attributeRemoved As Boolean = False
            Dim positionOfRemovedNode As Integer = -1
            Dim triviaOfRemovedNode As SyntaxTriviaList = Nothing
 
            ' Handle most cases
            Dim member = TryCast(destination, StatementSyntax)
            If member IsNot Nothing Then
                Dim newAttributeLists = RemoveAttributeFromAttributeLists(member.GetAttributes(), attributeToRemove, attributeRemoved, positionOfRemovedNode, triviaOfRemovedNode)
                VerifyAttributeRemoved(attributeRemoved)
                Dim newMember = member.WithAttributeLists(newAttributeLists)
                Return Cast(Of TDeclarationNode)(AppendTriviaAtPosition(newMember, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode))
            End If
 
            ' Handle global attributes
            Dim compilationUnit = TryCast(destination, CompilationUnitSyntax)
            If compilationUnit IsNot Nothing Then
                Dim attributeStatements = compilationUnit.Attributes
                Dim newAttributeStatements = RemoveAttributeFromAttributeStatements(attributeStatements, attributeToRemove, attributeRemoved, positionOfRemovedNode, triviaOfRemovedNode)
                VerifyAttributeRemoved(attributeRemoved)
                Dim newCompilationUnit = compilationUnit.WithAttributes(newAttributeStatements)
                Return Cast(Of TDeclarationNode)(AppendTriviaAtPosition(newCompilationUnit, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode))
            End If
 
            ' Handle parameters
            Dim parameter = TryCast(destination, ParameterSyntax)
            If parameter IsNot Nothing Then
                Dim newAttributeLists = RemoveAttributeFromAttributeLists(parameter.AttributeLists, attributeToRemove, attributeRemoved, positionOfRemovedNode, triviaOfRemovedNode)
                VerifyAttributeRemoved(attributeRemoved)
                Dim newParameter = parameter.WithAttributeLists(newAttributeLists)
                Return Cast(Of TDeclarationNode)(AppendTriviaAtPosition(newParameter, positionOfRemovedNode - destination.FullSpan.Start, triviaOfRemovedNode))
            End If
 
            Return destination
        End Function
 
        Private Shared Function RemoveAttributeFromAttributeLists(attributeLists As SyntaxList(Of AttributeListSyntax), attributeToRemove As SyntaxNode,
                                                                  <Out> ByRef attributeRemoved As Boolean, <Out> ByRef positionOfRemovedNode As Integer, <Out> ByRef triviaOfRemovedNode As SyntaxTriviaList) As SyntaxList(Of AttributeListSyntax)
            For Each attributeList In attributeLists
                Dim attributes = attributeList.Attributes
                If attributes.Any(Function(a) a Is attributeToRemove) Then
                    attributeRemoved = True
                    Dim trivia As IEnumerable(Of SyntaxTrivia) = Nothing
                    Dim newAttributeLists As IEnumerable(Of AttributeListSyntax) = Nothing
                    If attributes.Count = 1 Then
                        ' Remove the entire attribute list.
                        ComputePositionAndTriviaForRemoveAttributeList(attributeList, Function(t As SyntaxTrivia) t.IsKind(SyntaxKind.EndOfLineTrivia), positionOfRemovedNode, trivia)
                        newAttributeLists = attributeLists.Where(Function(aList) aList IsNot attributeList)
                    Else
                        ' Remove just the given attribute from the attribute list.
                        ComputePositionAndTriviaForRemoveAttributeFromAttributeList(attributeToRemove, Function(t As SyntaxToken) t.IsKind(SyntaxKind.CommaToken), positionOfRemovedNode, trivia)
                        Dim newAttributes = SyntaxFactory.SeparatedList(attributes.Where(Function(a) a IsNot attributeToRemove))
                        Dim newAttributeList = attributeList.WithAttributes(newAttributes)
                        newAttributeLists = attributeLists.Select(Function(attrList) If(attrList Is attributeList, newAttributeList, attrList))
                    End If
 
                    triviaOfRemovedNode = trivia.ToSyntaxTriviaList()
                    Return SyntaxFactory.List(newAttributeLists)
                End If
            Next
 
            attributeRemoved = False
            Return attributeLists
        End Function
 
        Private Shared Function RemoveAttributeFromAttributeStatements(attributeStatements As SyntaxList(Of AttributesStatementSyntax), attributeToRemove As SyntaxNode,
                                                                       <Out> ByRef attributeRemoved As Boolean, <Out> ByRef positionOfRemovedNode As Integer, <Out> ByRef triviaOfRemovedNode As SyntaxTriviaList) As SyntaxList(Of AttributesStatementSyntax)
            For Each attributeStatement In attributeStatements
                Dim attributeLists = attributeStatement.AttributeLists
                Dim newAttributeLists = RemoveAttributeFromAttributeLists(attributeLists, attributeToRemove, attributeRemoved, positionOfRemovedNode, triviaOfRemovedNode)
                If attributeRemoved Then
                    Dim newAttributeStatement = attributeStatement.WithAttributeLists(newAttributeLists)
                    Return SyntaxFactory.List(attributeStatements.Select(Function(attrStatement) If(attrStatement Is attributeStatement, newAttributeStatement, attrStatement)))
                End If
            Next
 
            attributeRemoved = False
            Return attributeStatements
        End Function
 
        Private Shared Sub VerifyAttributeRemoved(attributeRemoved As Boolean)
            If Not attributeRemoved Then
                Throw New ArgumentException("attributeToRemove")
            End If
        End Sub
 
        Public Overrides Function AddStatements(Of TDeclarationNode As SyntaxNode)(
                destinationMember As TDeclarationNode,
                statements As IEnumerable(Of SyntaxNode),
                options As VisualBasicCodeGenerationContextInfo,
                cancellationToken As CancellationToken) As TDeclarationNode
 
            Dim methodBlock = TryCast(destinationMember, MethodBlockBaseSyntax)
            If methodBlock IsNot Nothing Then
                Dim allStatements = methodBlock.Statements.Concat(StatementGenerator.GenerateStatements(statements))
 
                Dim result As Object
 
                Select Case methodBlock.Kind
                    Case SyntaxKind.SubBlock,
                        SyntaxKind.FunctionBlock
                        result = DirectCast(methodBlock, MethodBlockSyntax).WithStatements(SyntaxFactory.List(allStatements))
 
                    Case SyntaxKind.ConstructorBlock
                        result = DirectCast(methodBlock, ConstructorBlockSyntax).WithStatements(SyntaxFactory.List(allStatements))
 
                    Case SyntaxKind.OperatorBlock
                        result = DirectCast(methodBlock, OperatorBlockSyntax).WithStatements(SyntaxFactory.List(allStatements))
 
                    Case Else
                        result = DirectCast(methodBlock, AccessorBlockSyntax).WithStatements(SyntaxFactory.List(allStatements))
                End Select
 
                Return DirectCast(DirectCast(result, Object), TDeclarationNode)
            Else
                Return AddStatementsWorker(destinationMember, statements, options, cancellationToken)
            End If
        End Function
 
        Private Shared Function AddStatementsWorker(Of TDeclarationNode As SyntaxNode)(
                destinationMember As TDeclarationNode,
                statements As IEnumerable(Of SyntaxNode),
                options As VisualBasicCodeGenerationContextInfo,
                cancellationToken As CancellationToken) As TDeclarationNode
            Dim location = options.Context.BestLocation
            CheckLocation(destinationMember, location)
 
            Dim token = location.FindToken(cancellationToken)
            Dim oldBlock = token.Parent.GetContainingMultiLineExecutableBlocks().First
            Dim oldBlockStatements = oldBlock.GetExecutableBlockStatements()
            Dim oldBlockStatementsSet = oldBlockStatements.ToSet()
 
            Dim oldStatement = token.Parent.GetAncestorsOrThis(Of StatementSyntax)().First(AddressOf oldBlockStatementsSet.Contains)
            Dim oldStatementIndex = oldBlockStatements.IndexOf(oldStatement)
 
            Dim statementArray = statements.OfType(Of StatementSyntax).ToArray()
            Dim newBlock As SyntaxNode
            If options.Context.BeforeThisLocation IsNot Nothing Then
                Dim strippedTrivia As ImmutableArray(Of SyntaxTrivia) = Nothing
                Dim newStatement = VisualBasicFileBannerFacts.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(
                    oldStatement, strippedTrivia)
 
                statementArray(0) = statementArray(0).WithLeadingTrivia(strippedTrivia)
 
                newBlock = oldBlock.ReplaceNode(oldStatement, newStatement)
                newBlock = newBlock.ReplaceStatements(newBlock.GetExecutableBlockStatements().InsertRange(oldStatementIndex, statementArray))
            Else
                newBlock = oldBlock.ReplaceStatements(oldBlockStatements.InsertRange(oldStatementIndex + 1, statementArray))
            End If
 
            Return destinationMember.ReplaceNode(oldBlock, newBlock)
        End Function
 
        ' TODO Change to Not return null (https://github.com/dotnet/roslyn/issues/58243)
        Public Overrides Function CreateMethodDeclaration(method As IMethodSymbol,
                                                          destination As CodeGenerationDestination,
                                                          options As VisualBasicCodeGenerationContextInfo,
                                                          cancellationToken As CancellationToken) As SyntaxNode
            ' Synthesized methods for properties/events are not things we actually generate 
            ' declarations for.
            If method.AssociatedSymbol IsNot Nothing Then
                Return Nothing
            End If
 
            If method.IsConstructor() Then
                Return ConstructorGenerator.GenerateConstructorDeclaration(method, destination, options)
            ElseIf method.IsUserDefinedOperator() Then
                Return OperatorGenerator.GenerateOperatorDeclaration(method, options)
            ElseIf method.IsConversion() Then
                Return ConversionGenerator.GenerateConversionDeclaration(method, options)
            Else
                Return MethodGenerator.GenerateMethodDeclaration(method, destination, options)
            End If
        End Function
 
        Public Overrides Function CreateEventDeclaration([event] As IEventSymbol,
                                                         destination As CodeGenerationDestination,
                                                         options As VisualBasicCodeGenerationContextInfo,
                                                         cancellationToken As CancellationToken) As SyntaxNode
            Return EventGenerator.GenerateEventDeclaration([event], destination, options)
        End Function
 
        Public Overrides Function CreateFieldDeclaration(field As IFieldSymbol,
                                                         destination As CodeGenerationDestination,
                                                         options As VisualBasicCodeGenerationContextInfo,
                                                         cancellationToken As CancellationToken) As SyntaxNode
            If destination = CodeGenerationDestination.EnumType Then
                Return EnumMemberGenerator.GenerateEnumMemberDeclaration(field, Nothing, options)
            Else
                Return FieldGenerator.GenerateFieldDeclaration(field, destination, options)
            End If
        End Function
 
        Public Overrides Function CreatePropertyDeclaration([property] As IPropertySymbol,
                                                            destination As CodeGenerationDestination,
                                                            options As VisualBasicCodeGenerationContextInfo,
                                                            cancellationToken As CancellationToken) As SyntaxNode
            Return PropertyGenerator.GeneratePropertyDeclaration([property], destination, options)
        End Function
 
        Public Overrides Function CreateNamedTypeDeclaration(namedType As INamedTypeSymbol,
                                                             destination As CodeGenerationDestination,
                                                             options As VisualBasicCodeGenerationContextInfo,
                                                             cancellationToken As CancellationToken) As SyntaxNode
            Return NamedTypeGenerator.GenerateNamedTypeDeclaration(Me, namedType, options, cancellationToken)
        End Function
 
        Public Overrides Function CreateNamespaceDeclaration([namespace] As INamespaceSymbol,
                                                             destination As CodeGenerationDestination,
                                                             options As VisualBasicCodeGenerationContextInfo,
                                                             cancellationToken As CancellationToken) As SyntaxNode
            Return NamespaceGenerator.GenerateNamespaceDeclaration(Me, [namespace], options, cancellationToken)
        End Function
 
        Private Overloads Shared Function UpdateDeclarationModifiers(Of TDeclarationNode As SyntaxNode)(declaration As TDeclarationNode, computeNewModifiersList As Func(Of SyntaxTokenList, SyntaxTokenList)) As TDeclarationNode
            ' Handle type declarations
            Dim typeStatementSyntax = TryCast(declaration, TypeStatementSyntax)
            If typeStatementSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(typeStatementSyntax.WithModifiers(computeNewModifiersList(typeStatementSyntax.Modifiers)))
            End If
 
            ' Handle enum declarations
            Dim enumStatementSyntax = TryCast(declaration, EnumStatementSyntax)
            If enumStatementSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(enumStatementSyntax.WithModifiers(computeNewModifiersList(enumStatementSyntax.Modifiers)))
            End If
 
            ' Handle methods
            Dim methodBaseSyntax = TryCast(declaration, MethodBaseSyntax)
            If methodBaseSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(methodBaseSyntax.WithModifiers(computeNewModifiersList(methodBaseSyntax.Modifiers)))
            End If
 
            ' Handle Incomplete Members
            Dim incompleteMemberSyntax = TryCast(declaration, IncompleteMemberSyntax)
            If incompleteMemberSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(incompleteMemberSyntax.WithModifiers(computeNewModifiersList(incompleteMemberSyntax.Modifiers)))
            End If
 
            ' Handle fields
            Dim fieldDeclarationSyntax = TryCast(declaration, FieldDeclarationSyntax)
            If fieldDeclarationSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(fieldDeclarationSyntax.WithModifiers(computeNewModifiersList(fieldDeclarationSyntax.Modifiers)))
            End If
 
            ' Handle parameters
            Dim parameterSyntax = TryCast(declaration, ParameterSyntax)
            If parameterSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(parameterSyntax.WithModifiers(computeNewModifiersList(parameterSyntax.Modifiers)))
            End If
 
            ' Handle local declarations
            Dim localDeclarationStatementSyntax = TryCast(declaration, LocalDeclarationStatementSyntax)
            If localDeclarationStatementSyntax IsNot Nothing Then
                Return Cast(Of TDeclarationNode)(localDeclarationStatementSyntax.WithModifiers(computeNewModifiersList(localDeclarationStatementSyntax.Modifiers)))
            End If
 
            Return declaration
        End Function
 
        Public Overrides Function UpdateDeclarationModifiers(Of TDeclarationNode As SyntaxNode)(declaration As TDeclarationNode, newModifiers As IEnumerable(Of SyntaxToken), options As VisualBasicCodeGenerationContextInfo, cancellationToken As CancellationToken) As TDeclarationNode
            Dim computeNewModifiersList As Func(Of SyntaxTokenList, SyntaxTokenList) = Function(modifiersList As SyntaxTokenList)
                                                                                           Return SyntaxFactory.TokenList(newModifiers)
                                                                                       End Function
 
            Return UpdateDeclarationModifiers(declaration, computeNewModifiersList)
        End Function
 
        Public Overrides Function UpdateDeclarationAccessibility(Of TDeclarationNode As SyntaxNode)(declaration As TDeclarationNode, newAccessibility As Accessibility, options As VisualBasicCodeGenerationContextInfo, cancellationToken As CancellationToken) As TDeclarationNode
            Dim computeNewModifiersList As Func(Of SyntaxTokenList, SyntaxTokenList) = Function(modifiersList As SyntaxTokenList)
                                                                                           Return UpdateDeclarationAccessibility(modifiersList, newAccessibility, options)
                                                                                       End Function
 
            Return UpdateDeclarationModifiers(declaration, computeNewModifiersList)
        End Function
 
        Private Overloads Shared Function UpdateDeclarationAccessibility(modifiersList As SyntaxTokenList, newAccessibility As Accessibility, options As VisualBasicCodeGenerationContextInfo) As SyntaxTokenList
            Dim newModifierTokens As ArrayBuilder(Of SyntaxToken) = Nothing
            Using x = ArrayBuilder(Of SyntaxToken).GetInstance(newModifierTokens)
                AddAccessibilityModifiers(newAccessibility, newModifierTokens, CodeGenerationDestination.Unspecified, options, Accessibility.NotApplicable)
                If newModifierTokens.Count = 0 Then
                    Return modifiersList
                End If
 
                Return GetUpdatedDeclarationAccessibilityModifiers(
                    newModifierTokens, modifiersList,
                    Function(modifier) SyntaxFacts.IsAccessibilityModifier(modifier.Kind()))
            End Using
        End Function
 
        Private Shared Function UpdateSimpleAsClause(asClause As SimpleAsClauseSyntax, newType As ITypeSymbol) As SimpleAsClauseSyntax
            Dim newTypeSyntax = newType.GenerateTypeSyntax().
                WithLeadingTrivia(asClause.GetLeadingTrivia()).
                WithTrailingTrivia(asClause.GetTrailingTrivia())
 
            Return DirectCast(asClause, SimpleAsClauseSyntax).WithType(newTypeSyntax)
        End Function
 
        Private Shared Function UpdateAsClause(asClause As AsClauseSyntax, newType As ITypeSymbol) As AsClauseSyntax
            Dim newTypeSyntax = newType.GenerateTypeSyntax().
                WithLeadingTrivia(asClause.GetLeadingTrivia()).
                WithTrailingTrivia(asClause.GetTrailingTrivia())
 
            Select Case asClause.Kind
                Case SyntaxKind.SimpleAsClause
                    Return DirectCast(asClause, SimpleAsClauseSyntax).WithType(newTypeSyntax)
                Case Else
                    Dim asNewClause = DirectCast(asClause, AsNewClauseSyntax)
                    Dim newExpression = asNewClause.NewExpression
                    Dim updatedNewExpression As NewExpressionSyntax
                    Select Case newExpression.Kind
                        Case SyntaxKind.ArrayCreationExpression
                            updatedNewExpression = DirectCast(newExpression, ArrayCreationExpressionSyntax).WithType(newTypeSyntax)
                        Case SyntaxKind.ObjectCreationExpression
                            updatedNewExpression = DirectCast(newExpression, ObjectCreationExpressionSyntax).WithType(newTypeSyntax)
                        Case Else
                            Return asClause
                    End Select
 
                    Return asNewClause.WithNewExpression(updatedNewExpression)
            End Select
        End Function
 
        Public Overrides Function UpdateDeclarationType(Of TDeclarationNode As SyntaxNode)(declaration As TDeclarationNode, newType As ITypeSymbol, options As VisualBasicCodeGenerationContextInfo, cancellationToken As CancellationToken) As TDeclarationNode
            Dim syntaxNode = TryCast(declaration, VisualBasicSyntaxNode)
            If syntaxNode Is Nothing Then
                Return declaration
            End If
 
            Select Case syntaxNode.Kind
                Case SyntaxKind.SubStatement, SyntaxKind.FunctionStatement
                    Dim methodStatementSyntax = DirectCast(syntaxNode, MethodStatementSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(methodStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(methodStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.DeclareSubStatement, SyntaxKind.DeclareFunctionStatement
                    Dim declareStatementSyntax = DirectCast(syntaxNode, DeclareStatementSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(declareStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(declareStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.DelegateSubStatement, SyntaxKind.DelegateFunctionStatement
                    Dim delegateStatementSyntax = DirectCast(syntaxNode, DelegateStatementSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(delegateStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(delegateStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.EventStatement
                    Dim eventStatementSyntax = DirectCast(syntaxNode, EventStatementSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(eventStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(eventStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.OperatorStatement
                    Dim operatorStatementSyntax = DirectCast(syntaxNode, OperatorStatementSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(operatorStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(operatorStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.PropertyStatement
                    Dim propertyStatementSyntax = DirectCast(syntaxNode, PropertyStatementSyntax)
                    Dim newAsClause = UpdateAsClause(propertyStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(propertyStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.VariableDeclarator
                    Dim variableDeclaratorSyntax = DirectCast(syntaxNode, VariableDeclaratorSyntax)
                    Dim newAsClause = UpdateAsClause(variableDeclaratorSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(variableDeclaratorSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.Parameter
                    Dim parameterSyntax = DirectCast(syntaxNode, ParameterSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(parameterSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(parameterSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.CatchStatement
                    Dim catchStatementSyntax = DirectCast(syntaxNode, CatchStatementSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(catchStatementSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(catchStatementSyntax.WithAsClause(newAsClause))
 
                Case SyntaxKind.FunctionLambdaHeader, SyntaxKind.SubLambdaHeader
                    Dim lambdaHeaderSyntax = DirectCast(syntaxNode, LambdaHeaderSyntax)
                    Dim newAsClause = UpdateSimpleAsClause(lambdaHeaderSyntax.AsClause, newType)
                    Return Cast(Of TDeclarationNode)(lambdaHeaderSyntax.WithAsClause(newAsClause))
 
                Case Else
                    Return declaration
            End Select
        End Function
 
        Public Overrides Function UpdateDeclarationMembers(Of TDeclarationNode As SyntaxNode)(declaration As TDeclarationNode, newMembers As IList(Of ISymbol), options As VisualBasicCodeGenerationContextInfo, cancellationToken As CancellationToken) As TDeclarationNode
            Dim syntaxNode = TryCast(declaration, VisualBasicSyntaxNode)
            If syntaxNode IsNot Nothing Then
                Select Case syntaxNode.Kind
                    Case SyntaxKind.EnumBlock, SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ClassBlock
                        Return Cast(Of TDeclarationNode)(NamedTypeGenerator.UpdateNamedTypeDeclaration(Me, DirectCast(syntaxNode, StatementSyntax), newMembers, options, cancellationToken))
                    Case SyntaxKind.CompilationUnit, SyntaxKind.NamespaceBlock
                        Return Cast(Of TDeclarationNode)(NamespaceGenerator.UpdateCompilationUnitOrNamespaceDeclaration(Me, syntaxNode, newMembers, options, cancellationToken))
                End Select
            End If
 
            Return declaration
        End Function
    End Class
End Namespace