' 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.

Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator

    Friend NotInheritable Class MayHaveSideEffectsVisitor
        Inherits BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator

        Private _mayHaveSideEffects As Boolean

        Private Sub New()
        End Sub

        Friend Shared Function MayHaveSideEffects(node As BoundNode) As Boolean
            Dim visitor = New MayHaveSideEffectsVisitor()
            visitor.Visit(node)
            Return visitor._mayHaveSideEffects
        End Function

        Public Overrides Function Visit(node As BoundNode) As BoundNode
            If _mayHaveSideEffects Then
                Return Nothing
            End If

            Return MyBase.Visit(node)
        End Function

        Public Overrides Function VisitAssignmentOperator(node As BoundAssignmentOperator) As BoundNode
            Return SetMayHaveSideEffects()
        End Function

        ' Calls are treated as having side effects, but properties are
        ' not. (Since this visitor is run on the bound tree before
        ' lowering, properties are not represented as calls.)
        Public Overrides Function VisitCall(node As BoundCall) As BoundNode
            Return SetMayHaveSideEffects()
        End Function

        Public Overrides Function VisitLateInvocation(node As BoundLateInvocation) As BoundNode
            Return SetMayHaveSideEffects()
        End Function

        ' In Visual Basic, a parameterless method can be called without specifying an argument list,
        ' so we will treat every method group as a potential Call.  This is not strictly true (in the
        ' case where the parent is an AddressOf), but it doesn't seem worth any extra effort to handle
        ' that case differently (the consequence of saying that something may have side effects is
        ' simply that you may have to re-evaluate the expression manually).  The far more common case
        ' is encountered when getting the DataTip for a method invocation (the argument list is not
        ' included in the expression text).  We want to prevent automatic evaluation in that case.  
        Public Overrides Function VisitMethodGroup(node As BoundMethodGroup) As BoundNode
            Return SetMayHaveSideEffects()
        End Function

        Public Overrides Function VisitObjectInitializerExpression(node As BoundObjectInitializerExpression) As BoundNode
            For Each initializer In node.Initializers
                ' Do not treat initializer assignment as a side effect since it is
                ' part of an object creation. In short, visit the RHS only.
                Dim expr = If(initializer.Kind = BoundKind.AssignmentOperator,
                    DirectCast(initializer, BoundAssignmentOperator).Right,
                    initializer)
                Visit(expr)
            Next
            Return Nothing
        End Function

        Private Function SetMayHaveSideEffects() As BoundNode
            _mayHaveSideEffects = True
            Return Nothing
        End Function

    End Class

End Namespace
