File: src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\Extensions\ContextQuery\VisualBasicSyntaxContextExtensions.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.Runtime.CompilerServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
    Friend Module VisualBasicSyntaxTreeExtensions
 
        <Extension>
        Friend Function IsAccessibleEventContext(context As VisualBasicSyntaxContext, startAtEnclosingBaseType As Boolean) As Boolean
            If context.FollowsEndOfStatement Then
                Return False
            End If
 
            Dim targetToken = context.TargetToken
            If targetToken.IsChildToken(Of HandlesClauseSyntax)(Function(hc) hc.HandlesKeyword) OrElse
                targetToken.IsChildSeparatorToken(Function(hc As HandlesClauseSyntax) hc.Events) Then
 
                Dim container = context.EnclosingNamedType
                If container Is Nothing Then
                    Return False
                End If
 
                If startAtEnclosingBaseType Then
                    Return container.BaseType.GetAccessibleMembersInThisAndBaseTypes(Of IEventSymbol)(container).Any()
                End If
 
                Return container.GetAccessibleMembersInThisAndBaseTypes(Of IEventSymbol)(container).Any()
            End If
 
            Return False
        End Function
 
        <Extension()>
        Friend Function IsFollowingCompleteStatement(Of TParent As SyntaxNode)(context As VisualBasicSyntaxContext, childGetter As Func(Of TParent, StatementSyntax)) As Boolean
            Dim targetToken = context.TargetToken
 
            Dim parent = targetToken.GetAncestor(Of TParent)()
            If parent Is Nothing Then
                Return False
            End If
 
            Dim statement = childGetter(parent)
            If statement Is Nothing Then
                Return False
            End If
 
            Dim visitor As New IsStatementTerminatingTokenVisitor(targetToken)
            Return visitor.Visit(statement)
        End Function
 
        ''' <summary>
        ''' The specified position is immediately following a statement of one of the given kinds.
        ''' </summary>
        <Extension()>
        Friend Function IsAfterStatementOfKind(context As VisualBasicSyntaxContext, ParamArray kinds As SyntaxKind()) As Boolean
            If Not context.FollowsEndOfStatement Then
                Return False
            End If
 
            Dim targetToken = context.TargetToken
            If targetToken.Kind = SyntaxKind.None OrElse targetToken.Parent Is Nothing Then
                Return False
            End If
 
            Return targetToken.GetAncestor(Of StatementSyntax).IsKind(kinds)
        End Function
 
        <Extension()>
        Friend Function IsInStatementBlockOfKind(context As VisualBasicSyntaxContext, kind As SyntaxKind) As Boolean
            Return IsInStatementBlockHelper(context, Function(n, k) n.IsKind(k), kind)
        End Function
 
        <Extension()>
        Friend Function IsInStatementBlockOfKind(context As VisualBasicSyntaxContext, ParamArray kinds As SyntaxKind()) As Boolean
            Return IsInStatementBlockHelper(context, Function(n, k) n.IsKind(k), kinds)
        End Function
 
        Private Function IsInStatementBlockHelper(Of TArg)(context As VisualBasicSyntaxContext, predicate As Func(Of SyntaxNode, TArg, Boolean), arg As TArg) As Boolean
            Dim ancestor = context.TargetToken.Parent
 
            Do While ancestor IsNot Nothing
                If TypeOf ancestor Is EndBlockStatementSyntax Then
                    ' If we're within the End Block, skip the block itself
                    ancestor = ancestor.Parent.Parent
 
                    If ancestor Is Nothing Then
                        Return False
                    End If
                End If
 
                If predicate(ancestor, arg) Then
                    Return True
                End If
 
                If TypeOf ancestor Is LambdaExpressionSyntax Then
                    If Not (context.FollowsEndOfStatement AndAlso context.TargetToken = ancestor.GetLastToken()) Then
                        ' We should not look past lambdas
                        Return False
                    End If
                End If
 
                ancestor = ancestor.Parent
            Loop
 
            Return False
        End Function
 
        <Extension()>
        Public Function IsDelegateCreationContext(context As VisualBasicSyntaxContext) As Boolean
            If context.FollowsEndOfStatement Then
                Return False
            End If
 
            Dim token = context.TargetToken
            If token.Parent.IsKind(SyntaxKind.ArgumentList) AndAlso
               TypeOf token.Parent.Parent Is NewExpressionSyntax Then
 
                Dim symbolInfo = context.SemanticModel.GetSymbolInfo(DirectCast(token.Parent.Parent, NewExpressionSyntax).Type())
                Dim objectCreationType = TryCast(symbolInfo.Symbol, ITypeSymbol)
                If objectCreationType IsNot Nothing AndAlso
                   objectCreationType.TypeKind = TypeKind.Delegate Then
 
                    Return True
                End If
            End If
 
            Return False
        End Function
 
        <Extension()>
        Public Function CanDeclareCustomEventAccessor(context As VisualBasicSyntaxContext, accessorBlockKind As SyntaxKind) As Boolean
            If context.IsCustomEventContext Then
                Dim accessors = context.TargetToken.GetAncestor(Of EventBlockSyntax)().Accessors
                Return Not accessors.Any(Function(a) a.IsKind(accessorBlockKind)) AndAlso
                    Not accessors.Any(Function(a) a.Span.Contains(context.Position))
            End If
 
            Return False
        End Function
    End Module
End Namespace