File: src\Workspaces\SharedUtilitiesAndExtensions\Workspace\VisualBasic\Extensions\ContextQuery\SyntaxTokenExtensions.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 Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
    Friend Module SyntaxTokenExtensions
 
        <Extension>
        Friend Function HasColonBeforePosition(token As SyntaxToken, position As Integer) As Boolean
            Do
                If token.TrailingTrivia.Any(Function(t) t.IsKind(SyntaxKind.ColonTrivia) AndAlso t.Span.End <= position) Then
                    Return True
                End If
 
                token = token.GetNextToken(includeZeroWidth:=True)
            Loop While token.IsMissing
 
            Return False
        End Function
 
        Private Function CheckTrivia(triviaList As SyntaxTriviaList, position As Integer, ByRef checkForSecondEol As Boolean, ByRef allowsImplicitLineContinuation As Boolean) As Boolean
            For Each trivia In triviaList
                If trivia.IsKind(SyntaxKind.LineContinuationTrivia) AndAlso trivia.Span.End <= position Then
                    checkForSecondEol = True
                    allowsImplicitLineContinuation = False
                ElseIf trivia.IsKind(SyntaxKind.EndOfLineTrivia) AndAlso trivia.Span.End <= position Then
                    If Not allowsImplicitLineContinuation Then
                        If checkForSecondEol Then
                            checkForSecondEol = False
                        Else
                            Return True
                        End If
                    End If
 
                    allowsImplicitLineContinuation = False
                End If
            Next
 
            Return False
        End Function
 
        ''' <summary>
        ''' We need to check for EOL trivia not preceded by LineContinuation trivia.
        ''' 
        ''' This is slightly complicated since we need to get TrailingTrivia from missing tokens
        ''' and then get LeadingTrivia for the next non-missing token.
        ''' 
        ''' Note that this is even more complicated in the case that we're in structured trivia
        ''' because we might be part of the leading trivia to the next non-missing token.
        ''' </summary>
        <Extension>
        Friend Function HasNonContinuableEndOfLineBeforePosition(token As SyntaxToken, position As Integer, Optional checkForSecondEol As Boolean = False) As Boolean
            If token.FollowsBadEndDirective() Then
                Return False
            End If
 
            Dim allowsImplicitLineContinuation = token.Parent IsNot Nothing AndAlso
                                                 SyntaxFacts.AllowsTrailingImplicitLineContinuation(token)
 
            Dim originalToken = token
 
            Do
                If CheckTrivia(token.TrailingTrivia, position, checkForSecondEol, allowsImplicitLineContinuation) Then
                    Return True
                End If
 
                token = token.GetNextToken(includeZeroWidth:=True)
            Loop While token.IsMissing
 
            ' If our our original token was in structured trivia (such as preprocesser), it's entirely possible that the
            ' leading trivia of the next non-missing token might contain it. If that's the case, we don't want to check
            ' its leading trivia before it might have trivia that appear *before* the original token.
            '
            ' Consider the following example:
            '
            '   Class C
            '
            '     #Region $$
            '   End Class
            '
            ' In the code above, the original token is "Region", but the leading trivia to the next non-missing token ("End")
            ' includes the structured trivia containing the original token plus the trivia before it. In that case, we don't
            ' want to check the leading trivia of the "End".
 
            If Not token.LeadingTrivia.Span.Contains(originalToken.Span) Then
                Return CheckTrivia(token.LeadingTrivia, position, checkForSecondEol, allowsImplicitLineContinuation)
            Else
                Return False
            End If
        End Function
 
        <Extension>
        Friend Function FollowsBadEndDirective(targetToken As SyntaxToken) As Boolean
            If targetToken.IsKind(SyntaxKind.HashToken) AndAlso targetToken.TrailingTrivia.Any(Function(t)
                                                                                                   If t.HasStructure Then
                                                                                                       Dim childTokens = t.GetStructure().ChildTokens()
                                                                                                       Return childTokens.Count() = 1 AndAlso childTokens.First().IsKind(SyntaxKind.EndKeyword)
                                                                                                   End If
 
                                                                                                   Return False
                                                                                               End Function) Then
                Return targetToken.Parent.IsKind(SyntaxKind.BadDirectiveTrivia)
            End If
 
            Return targetToken.IsKind(SyntaxKind.EndKeyword) AndAlso
               targetToken.GetPreviousToken().IsKind(SyntaxKind.HashToken) AndAlso
               targetToken.GetPreviousToken().Parent.IsKind(SyntaxKind.BadDirectiveTrivia)
        End Function
 
        <Extension>
        Friend Function FollowsEndOfStatement(token As SyntaxToken, position As Integer) As Boolean
            Return token.HasColonBeforePosition(position) OrElse
                   token.HasNonContinuableEndOfLineBeforePosition(position)
        End Function
 
        <Extension>
        Friend Function MustBeginNewStatement(token As SyntaxToken, position As Integer) As Boolean
            Return token.HasColonBeforePosition(position) OrElse
                   token.HasNonContinuableEndOfLineBeforePosition(position, checkForSecondEol:=True)
        End Function
 
        <Extension>
        Friend Function IsMandatoryNamedParameterPosition(token As SyntaxToken) As Boolean
            If token.Kind() = SyntaxKind.CommaToken Then
                Dim argumentList = TryCast(token.Parent, ArgumentListSyntax)
                If argumentList Is Nothing Then
                    Return False
                End If
 
                For Each n In argumentList.Arguments.GetWithSeparators()
                    If n.IsToken AndAlso n.AsToken() = token Then
                        Return False
                    End If
 
                    If n.IsNode AndAlso DirectCast(n.AsNode(), ArgumentSyntax).IsNamed Then
                        Return True
                    End If
                Next
            End If
 
            Return False
        End Function
 
        <Extension()>
        Friend Function IsModifier(token As SyntaxToken) As Boolean
            Select Case token.Kind
                Case SyntaxKind.AsyncKeyword,
                     SyntaxKind.ConstKeyword,
                     SyntaxKind.DefaultKeyword,
                     SyntaxKind.PublicKeyword,
                     SyntaxKind.FriendKeyword,
                     SyntaxKind.ShadowsKeyword,
                     SyntaxKind.MustOverrideKeyword,
                     SyntaxKind.MustInheritKeyword,
                     SyntaxKind.PrivateKeyword,
                     SyntaxKind.NarrowingKeyword,
                     SyntaxKind.WideningKeyword,
                     SyntaxKind.NotInheritableKeyword,
                     SyntaxKind.NotOverridableKeyword,
                     SyntaxKind.OverloadsKeyword,
                     SyntaxKind.OverridableKeyword,
                     SyntaxKind.OverridesKeyword,
                     SyntaxKind.PartialKeyword,
                     SyntaxKind.ProtectedKeyword,
                     SyntaxKind.ReadOnlyKeyword,
                     SyntaxKind.WriteOnlyKeyword,
                     SyntaxKind.SharedKeyword,
                     SyntaxKind.WithEventsKeyword,
                     SyntaxKind.CustomKeyword,
                     SyntaxKind.IteratorKeyword
                    Return True
                Case Else
                    Return False
            End Select
        End Function
    End Module
End Namespace