<commit_before>﻿' Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Diagnostics
Imports System.Linq
Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Shared.Extensions

Namespace Microsoft.CodeAnalysis.VisualBasic.Utilities
    ''' <summary>
    ''' Helper class to analyze the semantic effects of a speculated syntax node replacement on the parenting nodes.
    ''' Given an expression node from a syntax tree and a new expression from a different syntax tree,
    ''' it replaces the expression with the new expression to create a speculated syntax tree.
    ''' It uses the original tree's semantic model to create a speculative semantic model and verifies that
    ''' the syntax replacement doesn't break the semantics of any parenting nodes of the original expression.
    ''' </summary>
    Friend Class SpeculationAnalyzer
        Inherits AbstractSpeculationAnalyzer(Of SyntaxNode, ExpressionSyntax, TypeSyntax, AttributeSyntax,
                                             ArgumentSyntax, ForEachStatementSyntax, ThrowStatementSyntax, SemanticModel)

        ''' <summary>
        ''' Creates a semantic analyzer for speculative syntax replacement.
        ''' </summary>
        ''' <param name="expression">Original expression to be replaced.</param>
        ''' <param name="newExpression">New expression to replace the original expression.</param>
        ''' <param name="semanticModel">Semantic model of <paramref name="expression"/> node's syntax tree.</param>
        ''' <param name="cancellationToken">Cancellation token.</param>
        ''' <param name="skipVerificationForReplacedNode">
        ''' True if semantic analysis should be skipped for the replaced node and performed starting from parent of the original and replaced nodes.
        ''' This could be the case when custom verifications are required to be done by the caller or
        ''' semantics of the replaced expression are different from the original expression.
        ''' </param>
        ''' <param name="failOnOverloadResolutionFailuresInOriginalCode">
        ''' True if semantic analysis should fail when any of the invocation expression ancestors of <paramref name="expression"/> in original code has overload resolution failures.
        ''' </param>        
        Public Sub New(expression As ExpressionSyntax, newExpression As ExpressionSyntax, semanticModel As SemanticModel, cancellationToken As CancellationToken, Optional skipVerificationForReplacedNode As Boolean = False, Optional failOnOverloadResolutionFailuresInOriginalCode As Boolean = False)
            MyBase.New(expression, newExpression, semanticModel, cancellationToken, skipVerificationForReplacedNode, failOnOverloadResolutionFailuresInOriginalCode)
        End Sub

        Protected Overrides Function GetSemanticRootForSpeculation(expression As ExpressionSyntax) As SyntaxNode
            Debug.Assert(expression IsNot Nothing)

            Dim parentNodeToSpeculate = expression _
                .AncestorsAndSelf(ascendOutOfTrivia:=False) _
                .Where(Function(node) CanSpeculateOnNode(node)) _
                .LastOrDefault()

            If parentNodeToSpeculate Is Nothing Then
                parentNodeToSpeculate = expression
            End If

            Return parentNodeToSpeculate
        End Function

        Public Shared Function CanSpeculateOnNode(node As SyntaxNode) As Boolean
            Return TypeOf node Is ExecutableStatementSyntax OrElse
                TypeOf node Is TypeSyntax OrElse
                node.Kind = SyntaxKind.Attribute OrElse
                node.Kind = SyntaxKind.EqualsValue OrElse
                node.Kind = SyntaxKind.AsNewClause OrElse
                node.Kind = SyntaxKind.RangeArgument
        End Function

        Protected Overrides Function GetSemanticRootOfReplacedExpression(semanticRootOfOriginalExpr As SyntaxNode, annotatedReplacedExpression As ExpressionSyntax) As SyntaxNode
            Dim originalExpression = Me.OriginalExpression

            ' Speculation is not supported for AsNewClauseSyntax nodes.
            ' Generate an EqualsValueSyntax node with the inner NewExpression of the AsNewClauseSyntax node for speculation.
            If semanticRootOfOriginalExpr.Kind = SyntaxKind.AsNewClause Then
                ' Because the original expression will change identity in the newly generated EqualsValueSyntax node,
                ' we annotate it here to allow us to get back to it after replace.
                Dim originalExprAnnotation = New SyntaxAnnotation()
                Dim annotatedOriginalExpression = originalExpression.WithAdditionalAnnotations(originalExprAnnotation)
                semanticRootOfOriginalExpr = semanticRootOfOriginalExpr.ReplaceNode(originalExpression, annotatedOriginalExpression)

                Dim asNewClauseNode = DirectCast(semanticRootOfOriginalExpr, AsNewClauseSyntax)
                semanticRootOfOriginalExpr = SyntaxFactory.EqualsValue(asNewClauseNode.NewExpression)
                semanticRootOfOriginalExpr = asNewClauseNode.CopyAnnotationsTo(semanticRootOfOriginalExpr)
                originalExpression = DirectCast(semanticRootOfOriginalExpr.GetAnnotatedNodesAndTokens(originalExprAnnotation).Single().AsNode(), ExpressionSyntax)
            End If

            Return semanticRootOfOriginalExpr.ReplaceNode(originalExpression, annotatedReplacedExpression)
        End Function

        Protected Overrides Sub ValidateSpeculativeSemanticModel(speculativeSemanticModel As SemanticModel, nodeToSpeculate As SyntaxNode)
            Debug.Assert(speculativeSemanticModel IsNot Nothing OrElse
                        TypeOf nodeToSpeculate Is ExpressionSyntax OrElse
                        Me.SemanticRootOfOriginalExpression.GetAncestors().Any(Function(node) node.IsKind(SyntaxKind.IncompleteMember)),
                        "SemanticModel.TryGetSpeculativeSemanticModel() API returned false.")<commit_msg>Handle top level speculation semantic model<commit_after>﻿' Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Diagnostics
Imports System.Linq
Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Shared.Extensions

Namespace Microsoft.CodeAnalysis.VisualBasic.Utilities
    ''' <summary>
    ''' Helper class to analyze the semantic effects of a speculated syntax node replacement on the parenting nodes.
    ''' Given an expression node from a syntax tree and a new expression from a different syntax tree,
    ''' it replaces the expression with the new expression to create a speculated syntax tree.
    ''' It uses the original tree's semantic model to create a speculative semantic model and verifies that
    ''' the syntax replacement doesn't break the semantics of any parenting nodes of the original expression.
    ''' </summary>
    Friend Class SpeculationAnalyzer
        Inherits AbstractSpeculationAnalyzer(Of SyntaxNode, ExpressionSyntax, TypeSyntax, AttributeSyntax,
                                             ArgumentSyntax, ForEachStatementSyntax, ThrowStatementSyntax, SemanticModel)

        ''' <summary>
        ''' Creates a semantic analyzer for speculative syntax replacement.
        ''' </summary>
        ''' <param name="expression">Original expression to be replaced.</param>
        ''' <param name="newExpression">New expression to replace the original expression.</param>
        ''' <param name="semanticModel">Semantic model of <paramref name="expression"/> node's syntax tree.</param>
        ''' <param name="cancellationToken">Cancellation token.</param>
        ''' <param name="skipVerificationForReplacedNode">
        ''' True if semantic analysis should be skipped for the replaced node and performed starting from parent of the original and replaced nodes.
        ''' This could be the case when custom verifications are required to be done by the caller or
        ''' semantics of the replaced expression are different from the original expression.
        ''' </param>
        ''' <param name="failOnOverloadResolutionFailuresInOriginalCode">
        ''' True if semantic analysis should fail when any of the invocation expression ancestors of <paramref name="expression"/> in original code has overload resolution failures.
        ''' </param>        
        Public Sub New(expression As ExpressionSyntax, newExpression As ExpressionSyntax, semanticModel As SemanticModel, cancellationToken As CancellationToken, Optional skipVerificationForReplacedNode As Boolean = False, Optional failOnOverloadResolutionFailuresInOriginalCode As Boolean = False)
            MyBase.New(expression, newExpression, semanticModel, cancellationToken, skipVerificationForReplacedNode, failOnOverloadResolutionFailuresInOriginalCode)
        End Sub

        Protected Overrides Function GetSemanticRootForSpeculation(expression As ExpressionSyntax) As SyntaxNode
            Debug.Assert(expression IsNot Nothing)

            Dim parentNodeToSpeculate = expression _
                .AncestorsAndSelf(ascendOutOfTrivia:=False) _
                .Where(Function(node) CanSpeculateOnNode(node)) _
                .LastOrDefault()

            If parentNodeToSpeculate Is Nothing Then
                parentNodeToSpeculate = expression
            End If

            Return parentNodeToSpeculate
        End Function

        Public Shared Function CanSpeculateOnNode(node As SyntaxNode) As Boolean
            Return TypeOf node Is ExecutableStatementSyntax OrElse
                TypeOf node Is TypeSyntax OrElse
                node.Kind = SyntaxKind.Attribute OrElse
                node.Kind = SyntaxKind.EqualsValue OrElse
                node.Kind = SyntaxKind.AsNewClause OrElse
                node.Kind = SyntaxKind.RangeArgument
        End Function

        Protected Overrides Function GetSemanticRootOfReplacedExpression(semanticRootOfOriginalExpr As SyntaxNode, annotatedReplacedExpression As ExpressionSyntax) As SyntaxNode
            Dim originalExpression = Me.OriginalExpression

            ' Speculation is not supported for AsNewClauseSyntax nodes.
            ' Generate an EqualsValueSyntax node with the inner NewExpression of the AsNewClauseSyntax node for speculation.
            If semanticRootOfOriginalExpr.Kind = SyntaxKind.AsNewClause Then
                ' Because the original expression will change identity in the newly generated EqualsValueSyntax node,
                ' we annotate it here to allow us to get back to it after replace.
                Dim originalExprAnnotation = New SyntaxAnnotation()
                Dim annotatedOriginalExpression = originalExpression.WithAdditionalAnnotations(originalExprAnnotation)
                semanticRootOfOriginalExpr = semanticRootOfOriginalExpr.ReplaceNode(originalExpression, annotatedOriginalExpression)

                Dim asNewClauseNode = DirectCast(semanticRootOfOriginalExpr, AsNewClauseSyntax)
                semanticRootOfOriginalExpr = SyntaxFactory.EqualsValue(asNewClauseNode.NewExpression)
                semanticRootOfOriginalExpr = asNewClauseNode.CopyAnnotationsTo(semanticRootOfOriginalExpr)
                originalExpression = DirectCast(semanticRootOfOriginalExpr.GetAnnotatedNodesAndTokens(originalExprAnnotation).Single().AsNode(), ExpressionSyntax)
            End If

            Return semanticRootOfOriginalExpr.ReplaceNode(originalExpression, annotatedReplacedExpression)
        End Function

        Protected Overrides Sub ValidateSpeculativeSemanticModel(speculativeSemanticModel As SemanticModel, nodeToSpeculate As SyntaxNode)
            Debug.Assert(speculativeSemanticModel IsNot Nothing OrElse
                        TypeOf nodeToSpeculate Is ExpressionSyntax OrElse
                        TypeOf nodeToSpeculate Is ExpressionStatementSyntax OrElse
                        Me.SemanticRootOfOriginalExpression.GetAncestors().Any(Function(node) node.IsKind(SyntaxKind.IncompleteMember)),
                        "SemanticModel.TryGetSpeculativeSemanticModel() API returned false.")
{'fraction_non_alphanumeric': 0.052511235512102815, 'fraction_numerical': 0.0003153827958684854, 'mean_word_length': 3.3995837669094695, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '829875', 'n_tokens_mistral': 2878, 'n_tokens_neox': 2749, 'n_words': 939}