File: Simplification\Reducers\AbstractVisualBasicReducer.AbstractReductionRewriter.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.Threading
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Simplification
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
    Partial Friend MustInherit Class AbstractVisualBasicReducer
        Friend MustInherit Class AbstractReductionRewriter
            Inherits VisualBasicSyntaxRewriter
            Implements IReductionRewriter
 
            Private ReadOnly _pool As ObjectPool(Of IReductionRewriter)
 
            Protected CancellationToken As CancellationToken
            Protected Property ParseOptions As VisualBasicParseOptions
            Private _simplificationOptions As VisualBasicSimplifierOptions
 
            Private ReadOnly _processedParentNodes As HashSet(Of SyntaxNode) = New HashSet(Of SyntaxNode)()
            Private _semanticModel As SemanticModel
 
            Private _hasMoreWork As Boolean
            Protected _alwaysSimplify As Boolean
 
            Protected Sub New(pool As ObjectPool(Of IReductionRewriter))
                _pool = pool
            End Sub
 
            Public Sub Initialize(parseOptions As ParseOptions, options As SimplifierOptions, cancellationToken As CancellationToken) Implements IReductionRewriter.Initialize
                Me.ParseOptions = DirectCast(parseOptions, VisualBasicParseOptions)
                _simplificationOptions = DirectCast(options, VisualBasicSimplifierOptions)
                Me.CancellationToken = cancellationToken
            End Sub
 
            Public Sub Dispose() Implements IDisposable.Dispose
                ParseOptions = Nothing
                _simplificationOptions = Nothing
                CancellationToken = CancellationToken.None
                _processedParentNodes.Clear()
                _semanticModel = Nothing
 
                _hasMoreWork = False
                _alwaysSimplify = False
 
                _pool.Free(Me)
            End Sub
 
            Public Sub RequireInitialized()
                Contract.ThrowIfNull(ParseOptions)
                Debug.Assert(_simplificationOptions IsNot Nothing)
                Debug.Assert(_semanticModel IsNot Nothing)
            End Sub
 
            Public ReadOnly Property HasMoreWork As Boolean Implements IReductionRewriter.HasMoreWork
                Get
                    Return _hasMoreWork
                End Get
            End Property
 
            Private Shared Function GetParentNode(expression As ExpressionSyntax) As SyntaxNode
                Return expression _
                    .AncestorsAndSelf() _
                    .OfType(Of ExpressionSyntax)() _
                    .LastOrDefault()
            End Function
 
            Private Shared Function GetParentNode(statement As StatementSyntax) As SyntaxNode
                Return statement _
                    .AncestorsAndSelf() _
                    .OfType(Of StatementSyntax)() _
                    .Where(Function(s) Not s.IsMemberBlock()) _
                    .LastOrDefault()
            End Function
 
            Protected Function SimplifyNode(Of TNode As SyntaxNode)(
                node As TNode,
                newNode As SyntaxNode,
                parentNode As SyntaxNode,
                simplifyFunc As Func(Of TNode, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxNode)
            ) As SyntaxNode
 
                RequireInitialized()
                Debug.Assert(parentNode IsNot Nothing)
 
                CancellationToken.ThrowIfCancellationRequested()
 
                If Not _alwaysSimplify AndAlso Not node.HasAnnotation(Simplifier.Annotation) Then
                    Return newNode
                End If
 
                If node IsNot newNode OrElse _processedParentNodes.Contains(parentNode) Then
                    _hasMoreWork = True
                    Return newNode
                End If
 
                If Not node.HasAnnotation(SimplificationHelpers.DoNotSimplifyAnnotation) Then
                    Dim simplifiedNode = simplifyFunc(node, _semanticModel, _simplificationOptions, CancellationToken)
                    If simplifiedNode IsNot node Then
                        _processedParentNodes.Add(parentNode)
                        _hasMoreWork = True
                        Return simplifiedNode
                    End If
                End If
 
                Return node
            End Function
 
            Protected Function SimplifyToken(
                token As SyntaxToken,
                newToken As SyntaxToken,
                simplifyFunc As Func(Of SyntaxToken, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxToken)
            ) As SyntaxToken
 
                If token.Kind = SyntaxKind.None Then
                    Return newToken
                End If
 
                Dim parentNode = token.Parent
 
                If TypeOf (parentNode) Is ExpressionSyntax Then
                    parentNode = GetParentNode(DirectCast(parentNode, ExpressionSyntax))
                ElseIf TypeOf (parentNode) Is StatementSyntax Then
                    parentNode = GetParentNode(DirectCast(parentNode, StatementSyntax))
                End If
 
                Debug.Assert(parentNode IsNot Nothing)
 
                CancellationToken.ThrowIfCancellationRequested()
 
                If Not _alwaysSimplify AndAlso Not token.HasAnnotation(Simplifier.Annotation) Then
                    Return newToken
                End If
 
                If token <> newToken OrElse _processedParentNodes.Contains(parentNode) Then
                    _hasMoreWork = True
                    Return newToken
                End If
 
                If Not token.HasAnnotation(SimplificationHelpers.DoNotSimplifyAnnotation) Then
                    Dim simplifiedToken = simplifyFunc(token, _semanticModel, _simplificationOptions, CancellationToken)
                    If simplifiedToken <> token Then
                        _processedParentNodes.Add(parentNode)
                        _hasMoreWork = True
 
                        Return simplifiedToken
                    End If
                End If
 
                Return newToken
            End Function
 
            Protected Function SimplifyExpression(Of TExpression As ExpressionSyntax)(
                expression As TExpression,
                newNode As SyntaxNode,
                simplifier As Func(Of TExpression, SemanticModel, VisualBasicSimplifierOptions, CancellationToken, SyntaxNode)
            ) As SyntaxNode
 
                Return SimplifyNode(expression, newNode, GetParentNode(expression), simplifier)
            End Function
 
            Protected Function SimplifyStatement(Of TStatement As StatementSyntax)(
                statement As TStatement,
                newNode As SyntaxNode,
                simplifier As Func(Of TStatement, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode)
            ) As SyntaxNode
 
                Return SimplifyNode(statement, newNode, GetParentNode(statement), simplifier)
            End Function
 
            Public Function VisitNodeOrToken(nodeOrToken As SyntaxNodeOrToken, semanticModel As SemanticModel, simplifyAllDescendants As Boolean) As SyntaxNodeOrToken Implements IReductionRewriter.VisitNodeOrToken
                _semanticModel = semanticModel
                _alwaysSimplify = simplifyAllDescendants
                _hasMoreWork = False
                _processedParentNodes.Clear()
 
                If nodeOrToken.IsNode Then
                    Return Visit(nodeOrToken.AsNode)
                Else
                    Return VisitToken(nodeOrToken.AsToken())
                End If
            End Function
 
            Public Overrides Function VisitAccessorBlock(node As AccessorBlockSyntax) As SyntaxNode
                Return VisitMethodBlockBase(node, Function(statements As SyntaxList(Of StatementSyntax)) node.WithStatements(statements))
            End Function
 
            Public Overrides Function VisitConstructorBlock(node As ConstructorBlockSyntax) As SyntaxNode
                Return VisitMethodBlockBase(node, Function(statements As SyntaxList(Of StatementSyntax)) node.WithStatements(statements))
            End Function
 
            Public Overrides Function VisitMethodBlock(node As MethodBlockSyntax) As SyntaxNode
                Return VisitMethodBlockBase(node, Function(statements As SyntaxList(Of StatementSyntax)) node.WithStatements(statements))
            End Function
 
            Public Overrides Function VisitOperatorBlock(node As OperatorBlockSyntax) As SyntaxNode
                Return VisitMethodBlockBase(node, Function(statements As SyntaxList(Of StatementSyntax)) node.WithStatements(statements))
            End Function
 
            Private Function VisitMethodBlockBase(node As MethodBlockBaseSyntax, updateFunc As Func(Of SyntaxList(Of StatementSyntax), MethodBlockBaseSyntax)) As MethodBlockBaseSyntax
                ' Certain reducers for VB (escaping, parentheses) require to operate on the entire method body, rather than individual statements.
                ' Hence, we need to reduce the entire method body as a single unit.
                ' However, there is no SyntaxNode for the method body or statement list, hence NodesAndTokensToReduceComputer added the MethodBlockBaseSyntax to the list of nodes to be reduced.
                ' Here we make sure that we reduce only the statement list inside the MethodBlockBaseSyntax.
 
                ' Note that if any of the nodes/tokens in the method declaration needed to be reduced, they would be handed separately to us and would be reduced appropriately.
 
                Dim rewrittenBody = VisitList(node.Statements)
                If Not rewrittenBody = node.Statements Then
                    Return updateFunc(rewrittenBody)
                End If
 
                Return node
            End Function
        End Class
    End Class
End Namespace