|
' 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 Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
' NOTE: The other partial class definition is generated by a tool.
' Because VB doesn't support Partial Module definitions the actual SyntaxFacts implementations are in this class
' but the SyntaxFacts extension methods are thin wrappers around this class exposed in separate Modules.
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Public Class SyntaxFacts
''' <summary>
''' Determine if the token instance represents a syntax trivia such as comment, whitespace, etc...
''' </summary>
Public Shared Function IsTrivia(this As SyntaxKind) As Boolean
Return IsSyntaxTrivia(this)
End Function
''' <summary>
''' Get all reserved and contextual keywords
''' </summary>
Public Shared Function GetKeywordKinds() As IEnumerable(Of SyntaxKind)
Return GetReservedKeywordKinds.Concat(GetContextualKeywordKinds)
End Function
''' <summary>
''' Helper to check whether the token is a predefined type
''' </summary>
''' <returns>True if it is a predefined type</returns>
Public Shared Function IsPredefinedType(kind As SyntaxKind) As Boolean
Return IsPredefinedTypeKeyword(kind)
End Function
''' <summary>
''' Helper to check whether the token is a predefined type OR Variant keyword
''' </summary>
''' <returns>True if it is a predefined type OR Variant keyword</returns>
Friend Shared Function IsPredefinedTypeOrVariant(kind As SyntaxKind) As Boolean
Return IsPredefinedTypeKeyword(kind) OrElse kind = SyntaxKind.VariantKeyword
End Function
''' <summary>
''' Returns true if the node is the object of an invocation expression
''' </summary>
Public Shared Function IsInvoked(node As ExpressionSyntax) As Boolean
node = SyntaxFactory.GetStandaloneExpression(node)
Dim inv = TryCast(node.Parent, InvocationExpressionSyntax)
Return inv IsNot Nothing AndAlso inv.Expression Is node
End Function
''' <summary>
''' Returns true if the node is the operand of an AddressOf expression
''' </summary>
Public Shared Function IsAddressOfOperand(node As ExpressionSyntax) As Boolean
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso parent.Kind = SyntaxKind.AddressOfExpression
End Function
''' <summary>
''' Returns true if the node is the operand of an AddressOf expression, or the object
''' of an invocation. This is used for special binding rules around the return value variable
''' inside Functions and Property Get accessors.
''' </summary>
Public Shared Function IsInvocationOrAddressOfOperand(node As ExpressionSyntax) As Boolean
Return IsInvoked(node) OrElse IsAddressOfOperand(node)
End Function
' Determines whether a particular node is in a context where it must bind to a type.
Public Shared Function IsInTypeOnlyContext(node As ExpressionSyntax) As Boolean
'Typeof does a null check and will result in returning false if nothing is passed rather than throwing an exception
If Not (TypeOf node Is TypeSyntax) Then
Return False ' Only nodes deriving from TypeSyntax could possible be in type context.
End If
Dim parent As VisualBasicSyntaxNode = node.Parent
If parent IsNot Nothing Then
Select Case parent.Kind
Case SyntaxKind.SimpleAsClause, SyntaxKind.AsNewClause
Return DirectCast(parent, AsClauseSyntax).Type Is node
Case SyntaxKind.GetTypeExpression
Return DirectCast(parent, GetTypeExpressionSyntax).Type Is node
Case SyntaxKind.TypeOfIsExpression, SyntaxKind.TypeOfIsNotExpression
Return DirectCast(parent, TypeOfExpressionSyntax).Type Is node
Case SyntaxKind.CTypeExpression, SyntaxKind.DirectCastExpression, SyntaxKind.TryCastExpression
Return DirectCast(parent, CastExpressionSyntax).Type Is node
Case SyntaxKind.TypeArgumentList
Return True ' all non-token children are types
Case SyntaxKind.InheritsStatement, SyntaxKind.ImplementsStatement
Return True ' all non-token children are types
Case SyntaxKind.TypeConstraint
Return True ' all non-token children are types
Case SyntaxKind.CrefSignaturePart
Return True ' all non-token children are types
Case SyntaxKind.Attribute
Return DirectCast(parent, AttributeSyntax).Name Is node
Case SyntaxKind.ObjectCreationExpression
Return DirectCast(parent, ObjectCreationExpressionSyntax).Type Is node
Case SyntaxKind.ArrayCreationExpression
Return DirectCast(parent, ArrayCreationExpressionSyntax).Type Is node
Case SyntaxKind.ArrayType
Return DirectCast(parent, ArrayTypeSyntax).ElementType Is node
Case SyntaxKind.NullableType
Return DirectCast(parent, NullableTypeSyntax).ElementType Is node
Case SyntaxKind.QualifiedName
Dim parentQualName = DirectCast(parent, QualifiedNameSyntax)
If parentQualName.Parent IsNot Nothing AndAlso parentQualName.Parent.Kind = SyntaxKind.ImplementsClause Then
Return parentQualName.Left Is node
Else
Return parentQualName.Right Is node
End If
Case SyntaxKind.TypedTupleElement
Return DirectCast(parent, TypedTupleElementSyntax).Type Is node
End Select
End If
Return False
End Function
' Is this node in a place where it bind to an implemented member.
Friend Shared Function IsImplementedMember(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso parent.IsKind(SyntaxKind.ImplementsClause)
End Function
' Is this node in a place where it bind to a handled event.
Friend Shared Function IsHandlesEvent(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso
parent.IsKind(SyntaxKind.HandlesClauseItem) AndAlso
TypeOf node Is IdentifierNameSyntax
End Function
' Is this node in a place where it bind to a handled event's container.
Friend Shared Function IsHandlesContainer(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Return TypeOf node Is WithEventsEventContainerSyntax
End Function
' Is this node in a place where it bind to a handled event's container.
Friend Shared Function IsHandlesProperty(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
Return parent IsNot Nothing AndAlso
parent.IsKind(SyntaxKind.WithEventsPropertyEventContainer) AndAlso
TypeOf node Is IdentifierNameSyntax
End Function
' Is this node in a place where is must bind to either a namespace or a type.
Public Shared Function IsInNamespaceOrTypeContext(node As SyntaxNode) As Boolean
If node IsNot Nothing Then
If TypeOf node IsNot TypeSyntax Then
Return False ' Only nodes deriving from TypeSyntax could possible be in type or namespace context.
End If
Dim parent = node.Parent
If parent IsNot Nothing Then
Select Case parent.Kind()
Case SyntaxKind.SimpleImportsClause
Return DirectCast(parent, SimpleImportsClauseSyntax).Name Is node
Case SyntaxKind.NamespaceStatement
Return DirectCast(parent, NamespaceStatementSyntax).Name Is node
Case SyntaxKind.QualifiedName
Dim parentQualName = DirectCast(parent, QualifiedNameSyntax)
If Not (parentQualName.Parent IsNot Nothing AndAlso parentQualName.Parent.Kind = SyntaxKind.ImplementsClause) Then
Return DirectCast(parent, QualifiedNameSyntax).Left Is node
End If
End Select
End If
Dim expressionNode = TryCast(node, ExpressionSyntax)
If expressionNode IsNot Nothing Then
Return IsInTypeOnlyContext(expressionNode)
End If
End If
Return False
End Function
''' <summary>
''' Determines if position is before or within the span of a node, or in the trailing trivia of a node
''' up to, but not including, a newline or colon trivia (which mark the end of a statement.)
''' </summary>
Private Shared Function InOrBeforeSpanOrEffectiveTrailingOfNode(node As SyntaxNode, position As Integer) As Boolean
Return position < node.SpanStart OrElse InSpanOrEffectiveTrailingOfNode(node, position)
End Function
''' <summary>
''' Determines if position is within the span of a node, or in the trailing trivia of a node
''' up to, but not including, a newline or colon trivia (which mark the end of a statement.)
''' </summary>
Friend Shared Function InSpanOrEffectiveTrailingOfNode(node As SyntaxNode, position As Integer) As Boolean
Dim span = node.Span
If span.Contains(position) Then
Return True
ElseIf position >= span.End AndAlso position < node.FullSpan.End Then
' Position is in the trailing trivia of node. Check for newline or :.
Dim trailingTrivia As SyntaxTriviaList = node.GetTrailingTrivia()
For Each trivia In trailingTrivia
If trivia.Kind = SyntaxKind.EndOfLineTrivia OrElse trivia.Kind = SyntaxKind.ColonTrivia Then
Exit For
End If
If trivia.FullSpan.Contains(position) Then
Return True
End If
Next
' The effective trailing trivia didn't contain the position
Return False
End If
Return False
End Function
' Determines if possibleBlock is a block statement and position is in the interior.
' If so, then return true.
Friend Shared Function InBlockInterior(possibleBlock As SyntaxNode, position As Integer) As Boolean
Dim body As SyntaxList(Of StatementSyntax) = Nothing
Return InBlockInterior(possibleBlock, position, body)
End Function
''' <summary>
''' Determines if possibleLambda is a lambda expression and position is in the interior.
''' </summary>
Friend Shared Function InLambdaInterior(
possibleLambda As SyntaxNode,
position As Integer
) As Boolean
Dim afterBegin As Boolean
Dim beforeEnd As Boolean
Select Case possibleLambda.Kind()
Case SyntaxKind.SingleLineFunctionLambdaExpression,
SyntaxKind.SingleLineSubLambdaExpression
Dim singleLineLambda = DirectCast(possibleLambda, SingleLineLambdaExpressionSyntax)
Dim parameterList As ParameterListSyntax = singleLineLambda.SubOrFunctionHeader.ParameterList
If parameterList Is Nothing OrElse parameterList.CloseParenToken.IsMissing Then
afterBegin = (position >= singleLineLambda.SubOrFunctionHeader.Span.End)
Else
afterBegin = (position >= parameterList.CloseParenToken.SpanStart)
End If
beforeEnd = (position <= singleLineLambda.Body.Span.End)
Case SyntaxKind.MultiLineFunctionLambdaExpression,
SyntaxKind.MultiLineSubLambdaExpression
Dim multiLineLambda = DirectCast(possibleLambda, MultiLineLambdaExpressionSyntax)
Dim parameterList As ParameterListSyntax = multiLineLambda.SubOrFunctionHeader.ParameterList
If parameterList Is Nothing OrElse parameterList.CloseParenToken.IsMissing Then
afterBegin = (position >= multiLineLambda.SubOrFunctionHeader.Span.End)
Else
afterBegin = (position >= parameterList.CloseParenToken.SpanStart)
End If
beforeEnd = (position < multiLineLambda.EndSubOrFunctionStatement.SpanStart)
Case Else
Return False
End Select
Return afterBegin AndAlso beforeEnd
End Function
' Determines if possibleBlock is a block statement and position is in the interior.
' If so, then return true and the body.
Friend Shared Function InBlockInterior(possibleBlock As SyntaxNode,
position As Integer,
ByRef body As SyntaxList(Of StatementSyntax)) As Boolean
Dim beginStatement As StatementSyntax = Nothing
Dim endStatement As StatementSyntax = Nothing
Dim beginTerminator As SyntaxToken = Nothing
If IsBlockStatement(possibleBlock, beginStatement, beginTerminator, body, endStatement) Then
Dim afterBegin As Boolean = True
Dim beforeEnd As Boolean = True
If beginTerminator.Kind <> SyntaxKind.None AndAlso beginTerminator.Width > 0 Then
afterBegin = position >= beginTerminator.SpanStart
Else
afterBegin = Not InOrBeforeSpanOrEffectiveTrailingOfNode(beginStatement, position)
End If
If endStatement Is Nothing Then
Select Case possibleBlock.Kind
Case SyntaxKind.SingleLineIfStatement, SyntaxKind.SingleLineElseClause
' No expected end statement. These are "single" line blocks, check based on last statement in block instead.
If body.Count > 0 Then
Dim lastStatement = body(body.Count - 1)
beforeEnd = InOrBeforeSpanOrEffectiveTrailingOfNode(lastStatement, position)
End If
Case Else
' No expected end statement. These are multi-line blocks, check based on a token that follows the block instead.
Dim followingToken As SyntaxToken = possibleBlock.GetLastToken(includeZeroWidth:=True).GetNextToken()
If followingToken <> Nothing Then
' These blocks are always followed by a construct that terminates them. Let's treat it similar to the endStatement.
beforeEnd = position < followingToken.SpanStart
End If
End Select
ElseIf endStatement.Width > 0 Then
beforeEnd = InOrBeforeSpanOrEffectiveTrailingOfNode(endStatement, position)
End If
Return afterBegin AndAlso beforeEnd
End If
Return False
End Function
' Returns is possibleBlock is a block statement. If so, return the begin, body, and end statement. Note that
' many blocks (IfPart, TryPart, CaseBlock, etc. ) do not have immediate end statements. Also a few blocks don't
' have bodies that are SeparatedSyntaxList(Of StatementSyntax).
'
' Only for single-line If And Else, also return the token that ends that "begin" part (Then or Else tokens).
Friend Shared Function IsBlockStatement(possibleBlock As SyntaxNode,
ByRef beginStatement As StatementSyntax,
ByRef beginTerminator As SyntaxToken,
ByRef body As SyntaxList(Of StatementSyntax),
ByRef endStatement As StatementSyntax) As Boolean
beginTerminator = Nothing
Select Case possibleBlock.Kind()
Case SyntaxKind.NamespaceBlock
Dim nsBlock = DirectCast(possibleBlock, NamespaceBlockSyntax)
beginStatement = nsBlock.NamespaceStatement
body = nsBlock.Members
endStatement = nsBlock.EndNamespaceStatement
Return True
Case SyntaxKind.ModuleBlock, SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ClassBlock
Dim typeBlock = DirectCast(possibleBlock, TypeBlockSyntax)
beginStatement = typeBlock.BlockStatement
body = typeBlock.Members
endStatement = typeBlock.EndBlockStatement
Return True
Case SyntaxKind.EnumBlock
Dim enumBlock = DirectCast(possibleBlock, EnumBlockSyntax)
beginStatement = enumBlock.EnumStatement
body = enumBlock.Members
endStatement = enumBlock.EndEnumStatement
Return True
Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock, SyntaxKind.ConstructorBlock,
SyntaxKind.OperatorBlock, SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock,
SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock
Dim methodBlock = DirectCast(possibleBlock, MethodBlockBaseSyntax)
beginStatement = methodBlock.BlockStatement
body = methodBlock.Statements
endStatement = methodBlock.EndBlockStatement
Return True
Case SyntaxKind.PropertyBlock
Dim propertyBlock = DirectCast(possibleBlock, PropertyBlockSyntax)
beginStatement = propertyBlock.PropertyStatement
body = Nothing ' doesn't have a body per se
endStatement = propertyBlock.EndPropertyStatement
Return True
Case SyntaxKind.EventBlock
Dim eventBlock = DirectCast(possibleBlock, EventBlockSyntax)
beginStatement = eventBlock.EventStatement
body = Nothing ' doesn't have a body per se
endStatement = eventBlock.EndEventStatement
Return True
Case SyntaxKind.WhileBlock
Dim whileBlock = DirectCast(possibleBlock, WhileBlockSyntax)
beginStatement = whileBlock.WhileStatement
body = whileBlock.Statements
endStatement = whileBlock.EndWhileStatement
Return True
Case SyntaxKind.ForBlock, SyntaxKind.ForEachBlock
Dim forBlock = DirectCast(possibleBlock, ForOrForEachBlockSyntax)
beginStatement = forBlock.ForOrForEachStatement
body = forBlock.Statements
endStatement = forBlock.NextStatement
Return True
Case SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock,
SyntaxKind.DoUntilLoopBlock,
SyntaxKind.DoLoopWhileBlock,
SyntaxKind.DoLoopUntilBlock
Dim doBlock = DirectCast(possibleBlock, DoLoopBlockSyntax)
beginStatement = doBlock.DoStatement
body = doBlock.Statements
endStatement = doBlock.LoopStatement
Return True
Case SyntaxKind.UsingBlock
Dim usingBlock = DirectCast(possibleBlock, UsingBlockSyntax)
beginStatement = usingBlock.UsingStatement
body = usingBlock.Statements
endStatement = usingBlock.EndUsingStatement
Return True
Case SyntaxKind.SyncLockBlock
Dim syncBlock = DirectCast(possibleBlock, SyncLockBlockSyntax)
beginStatement = syncBlock.SyncLockStatement
body = syncBlock.Statements
endStatement = syncBlock.EndSyncLockStatement
Return True
Case SyntaxKind.WithBlock
Dim withBlock = DirectCast(possibleBlock, WithBlockSyntax)
beginStatement = withBlock.WithStatement
body = withBlock.Statements
endStatement = withBlock.EndWithStatement
Return True
Case SyntaxKind.SelectBlock
Dim selectBlock = DirectCast(possibleBlock, SelectBlockSyntax)
beginStatement = selectBlock.SelectStatement
body = Nothing ' doesn't fit
endStatement = selectBlock.EndSelectStatement
Return True
Case SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock
Dim caseBlock = DirectCast(possibleBlock, CaseBlockSyntax)
beginStatement = caseBlock.CaseStatement
body = caseBlock.Statements
endStatement = Nothing ' doesn't fit
Return True
Case SyntaxKind.SingleLineIfStatement
Dim ifStatement = DirectCast(possibleBlock, SingleLineIfStatementSyntax)
beginStatement = Nothing ' doesn't fit
beginTerminator = ifStatement.ThenKeyword
body = ifStatement.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.SingleLineElseClause
Dim elseClause = DirectCast(possibleBlock, SingleLineElseClauseSyntax)
beginStatement = Nothing ' doesn't fit
beginTerminator = elseClause.ElseKeyword
body = elseClause.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.MultiLineIfBlock
Dim ifBlock = DirectCast(possibleBlock, MultiLineIfBlockSyntax)
beginStatement = ifBlock.IfStatement
body = ifBlock.Statements
endStatement = ifBlock.EndIfStatement
Return True
Case SyntaxKind.ElseIfBlock
Dim elseIfBlock = DirectCast(possibleBlock, ElseIfBlockSyntax)
beginStatement = elseIfBlock.ElseIfStatement
body = elseIfBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.ElseBlock
Dim elseBlock = DirectCast(possibleBlock, ElseBlockSyntax)
beginStatement = elseBlock.ElseStatement
body = elseBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.TryBlock
Dim tryBlock = DirectCast(possibleBlock, TryBlockSyntax)
beginStatement = tryBlock.TryStatement
body = tryBlock.Statements
endStatement = tryBlock.EndTryStatement
Return True
Case SyntaxKind.CatchBlock
Dim catchBlock = DirectCast(possibleBlock, CatchBlockSyntax)
beginStatement = catchBlock.CatchStatement
body = catchBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case SyntaxKind.FinallyBlock
Dim finallyBlock = DirectCast(possibleBlock, FinallyBlockSyntax)
beginStatement = finallyBlock.FinallyStatement
body = finallyBlock.Statements
endStatement = Nothing ' doesn't have an end.
Return True
Case Else
Return False
End Select
End Function
''' <summary>
''' If "node" is a block statement return the Begin statement of "node", otherwise return "node".
''' </summary>
Friend Shared Function BeginOfBlockStatementIfAny(node As SyntaxNode) As SyntaxNode
Dim beginStatement As StatementSyntax = Nothing
Dim body As SyntaxList(Of StatementSyntax) = Nothing
Dim endStatement As StatementSyntax = Nothing
Dim beginTerminator As SyntaxToken = Nothing
If IsBlockStatement(node, beginStatement, beginTerminator, body, endStatement) Then
If beginStatement IsNot Nothing Then
Return beginStatement
End If
End If
Return node
End Function
Public Shared Function GetText(accessibility As Accessibility) As String
Select Case accessibility
Case Accessibility.Friend
Return GetText(SyntaxKind.FriendKeyword)
Case Accessibility.NotApplicable
Return String.Empty
Case Accessibility.Private
Return GetText(SyntaxKind.PrivateKeyword)
Case Accessibility.Protected
Return GetText(SyntaxKind.ProtectedKeyword)
Case Accessibility.ProtectedAndFriend
Return GetText(SyntaxKind.PrivateKeyword) + " " + GetText(SyntaxKind.ProtectedKeyword)
Case Accessibility.ProtectedOrFriend
Return GetText(SyntaxKind.ProtectedKeyword) + " " + GetText(SyntaxKind.FriendKeyword)
Case Accessibility.Public
Return GetText(SyntaxKind.PublicKeyword)
Case Else
Debug.Assert(False, String.Format("Unknown accessibility '{0}'", accessibility))
Return Nothing
End Select
End Function
Public Shared Function IsAnyToken(kind As SyntaxKind) As Boolean
Return kind >= SyntaxKind.AddHandlerKeyword AndAlso kind <= SyntaxKind.CharacterLiteralToken
End Function
Public Shared Function GetUnaryExpression(token As SyntaxKind) As SyntaxKind
Select Case token
Case SyntaxKind.PlusToken
Return SyntaxKind.UnaryPlusExpression
Case SyntaxKind.MinusToken
Return SyntaxKind.UnaryMinusExpression
Case SyntaxKind.NotKeyword
Return SyntaxKind.NotExpression
Case SyntaxKind.AddressOfKeyword
Return SyntaxKind.AddressOfExpression
Case Else
Return SyntaxKind.None
End Select
End Function
Public Shared Function IsPreprocessorPunctuation(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.HashToken
End Function
Public Shared Function IsLanguagePunctuation(kind As SyntaxKind) As Boolean
Return IsPunctuation(kind) AndAlso Not IsPreprocessorPunctuation(kind)
End Function
Public Shared Function IsName(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.IdentifierName OrElse
kind = SyntaxKind.GenericName OrElse
kind = SyntaxKind.QualifiedName OrElse
kind = SyntaxKind.GlobalName
End Function
Public Shared Function IsNamespaceMemberDeclaration(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.ClassStatement OrElse kind = SyntaxKind.InterfaceStatement OrElse
kind = SyntaxKind.StructureStatement OrElse kind = SyntaxKind.EnumStatement OrElse
kind = SyntaxKind.ModuleStatement OrElse kind = SyntaxKind.NamespaceStatement OrElse
kind = SyntaxKind.DelegateFunctionStatement OrElse kind = SyntaxKind.DelegateSubStatement
End Function
Public Shared Function IsPunctuationOrKeyword(kind As SyntaxKind) As Boolean
Select Case kind
Case SyntaxKind.AddHandlerKeyword To SyntaxKind.EndOfXmlToken,
SyntaxKind.NameOfKeyword,
SyntaxKind.DollarSignDoubleQuoteToken,
SyntaxKind.EndOfInterpolatedStringToken
Return True
Case Else
Return False
End Select
End Function
Public Shared Function VarianceKindFromToken(token As SyntaxToken) As VarianceKind
Select Case token.Kind
Case SyntaxKind.OutKeyword
Return VarianceKind.Out
Case SyntaxKind.InKeyword
Return VarianceKind.In
Case Else
Return VarianceKind.None
End Select
End Function
''' <summary>
''' Checks if the SyntaxNode is an attribute name. To be an attribute name, the syntax
''' must be parented by an Attribute and the node itself must be equal to the Attribute.Name
''' property.
''' </summary>
Public Shared Function IsAttributeName(node As SyntaxNode) As Boolean
Dim nextNode As SyntaxNode = node
Do While nextNode IsNot Nothing
Select Case nextNode.Kind()
Case SyntaxKind.IdentifierName, SyntaxKind.QualifiedName
nextNode = nextNode.Parent
Case SyntaxKind.Attribute
Dim attribute = DirectCast(nextNode, AttributeSyntax)
If attribute.Name Is node Then
Return True
End If
Dim name As QualifiedNameSyntax = TryCast(attribute.Name, QualifiedNameSyntax)
Return name IsNot Nothing AndAlso name.Right Is node
Case Else
Return False
End Select
Loop
Return False
End Function
''' <summary>
''' Is the node the name of a named argument of an invocation or object creation expression,
''' but not an attribute.
''' </summary>
Public Shared Function IsNamedArgumentName(node As SyntaxNode) As Boolean
If node.Kind <> SyntaxKind.IdentifierName Then
Return False
End If
Dim parent1 = TryCast(node.Parent, NameColonEqualsSyntax)
If parent1 Is Nothing Then
Return False
End If
Dim parent2 = parent1.Parent.Parent
If parent2 Is Nothing OrElse Not parent2.IsKind(SyntaxKind.ArgumentList) Then
Return False
End If
Dim parent3 = parent2.Parent
If parent3 Is Nothing Then
Return False
End If
Select Case parent3.Kind
Case SyntaxKind.InvocationExpression,
SyntaxKind.ObjectCreationExpression,
SyntaxKind.RaiseEventStatement
Return True
Case Else
Return False
End Select
End Function
''' <summary>
''' Return keyword or punctuation text based on SyntaxKind
''' </summary>
Public Shared Function GetBlockName(kind As SyntaxKind) As String
Select Case kind
Case SyntaxKind.CaseBlock
Return "Case"
Case SyntaxKind.SimpleDoLoopBlock,
SyntaxKind.DoWhileLoopBlock,
SyntaxKind.DoUntilLoopBlock,
SyntaxKind.DoLoopWhileBlock,
SyntaxKind.DoLoopUntilBlock
Return "Do Loop"
Case SyntaxKind.WhileBlock
Return "While"
Case SyntaxKind.WithBlock
Return "With"
Case SyntaxKind.SyncLockBlock
Return "SyncLock"
Case SyntaxKind.UsingBlock
Return "Using"
Case SyntaxKind.ForBlock
Return "For"
Case SyntaxKind.ForEachBlock
Return "For Each"
Case SyntaxKind.SelectBlock
Return "Select"
Case SyntaxKind.MultiLineIfBlock
Return "If"
Case SyntaxKind.ElseIfBlock
Return "Else If"
Case SyntaxKind.ElseBlock
Return "Else"
Case SyntaxKind.TryBlock
Return "Try"
Case SyntaxKind.CatchBlock
Return "Catch"
Case SyntaxKind.FinallyBlock
Return "Finally"
Case Else
Throw New ArgumentOutOfRangeException(NameOf(kind))
End Select
End Function
''' <summary>
''' Indicates whether a newline may validly follow the specified SyntaxToken without requiring an explicit line continuation sequence ' _' or terminating the containing statement.
''' </summary>
''' <param name="token">The token to test. This token must be parented by a SyntaxNode.</param>
''' <returns>True if implicit line continuation is allowed after token.</returns>
''' <remarks>
''' <para>Refer to "Statements in Visual Basic", 2010 version, http://msdn.microsoft.com/en-us/library/865x40k4(v=vs.100).aspx
''' for examples.</para>
''' <para>Implicit line continuation may be used in Visual Basic: </para>
''' <list>
''' <item>After a comma (,).</item>
''' <item>After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.</item>
''' <item>After an open parenthesis (() or before a closing parenthesis ()).</item>
''' <item>After an open curly brace ({) or before a closing curly brace (}).</item>
''' <item>After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.</item>
''' <item>
''' <para>Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
''' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).</para>
''' <para>You cannot break a line between the keywords of query operators that are made up of multiple keywords
''' (Order By, Group Join, Take While, and Skip While).</para>
''' </item>
''' <item>After the concatenation operator (&).</item>
''' <item>After assignment operators (=, &=, :=, +=, -=, *=, /=, \=, ^=, <<=, >>=).</item>
''' <item>After binary operators (+, -, /, *, Mod, <>, <, >, <=, >=, ^, >>, <<, And, AndAlso, Or, OrElse, Like, Xor) within an expression.</item>
''' <item>After the Is and IsNot operators.</item>
''' <item>After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.</item>
''' <item>
''' <para>Also after a greater-than sign (>) when you specify an attribute.</para>
''' <para>However, you must include a line-continuation character (_) when you specify assembly-level or module-level attributes.</para>
''' </item>
''' <item>
''' <para>After a member qualifier character (.) and before the member name.</para>
''' <para>However, you must include a line-continuation character (_) following a member qualifier character when you are using the With statement or
''' supplying values in the initialization list for a type.</para>
''' </item>
''' <item>
''' <para>After an XML axis property qualifier (. or ...).</para>
''' <para>However, you must include a line-continuation character (_) when you specify a member qualifier when you are using the With keyword.</para>
''' </item>
''' <item>After the From keyword in a collection initializer.</item>
''' <item>After the With keyword in a member initializer.</item>
''' <item>After the In keyword in a For Each statement.</item>
''' </list>
''' </remarks>
Public Shared Function AllowsTrailingImplicitLineContinuation(token As SyntaxToken) As Boolean
If token.Parent Is Nothing Then Throw New ArgumentException("'token' must be parented by a SyntaxNode.")
Dim kind = token.Kind
Dim parentKind = token.Parent.Kind
' This list taken from: "Statements in Visual Basic", 2010 version, http://msdn.microsoft.com/en-us/library/865x40k4(v=vs.100).aspx
' After a comma (,).
If kind = SyntaxKind.CommaToken Then Return True
' Disallowed after unary minus and plus.
If kind = SyntaxKind.MinusToken OrElse kind = SyntaxKind.PlusToken Then
Return TypeOf token.Parent Is BinaryExpressionSyntax
End If
' Disallowed after xml namespace imports
If kind = SyntaxKind.GreaterThanToken AndAlso parentKind = SyntaxKind.XmlNamespaceImportsClause Then
Return False
End If
' After the concatenation operator (&).
' After assignment operators (=, &=, :=, +=, -=, *=, /=, \=, ^=, <<=, >>=).
' After binary operators (+, -, /, *, Mod, <>, <, >, <=, >=, ^, >>, <<, And, AndAlso, Or, OrElse, Like, Xor) within an expression.
' After the Is and IsNot operators.
' These cases are also covered by the binary operator check.
' After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.
' Also after a greater-than sign (>) when you specify an attribute.
' NOTE: No idea what this means:
' However, you must include a line-continuation character (_) when you specify assembly-level or module-level attributes.
If IsBinaryExpressionOperatorToken(kind) OrElse IsAssignmentStatementOperatorToken(kind) Then Return True
Select Case kind
Case SyntaxKind.ColonEqualsToken
Return True
' After an open parenthesis (() or before a closing parenthesis ()).
' After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.
Case SyntaxKind.OpenParenToken,
SyntaxKind.LessThanPercentEqualsToken,
SyntaxKind.PercentGreaterThanToken
Return True
' After an open curly brace ({) or before a closing curly brace (})
' However, a line-continuation character is required following the open curly brace of a string interpolation.
Case SyntaxKind.OpenBraceToken
If parentKind = SyntaxKind.Interpolation Then
Return False
End If
Return True
' After a member qualifier character (.) and before the member name.
' However, you must include a line-continuation character (_) following a member qualifier character when you are using the With statement or
' supplying values in the initialization list for a type.
Case SyntaxKind.DotToken
' bug # 12903
' when dot is directly under named field initializer, (_) is needed between "." and member name
If parentKind = SyntaxKind.NamedFieldInitializer Then
Return False
ElseIf parentKind = SyntaxKind.SimpleMemberAccessExpression Then
Return CType(token.Parent, MemberAccessExpressionSyntax).Expression IsNot Nothing OrElse
token.Parent.Parent.Kind = SyntaxKind.NamedFieldInitializer
' After an XML axis property qualifier (. or .@ or ...).
' However, you must include a line-continuation character (_) when you specify a member qualifier when you are using the With keyword.
' BUG: Dev11 doesn't allow after the @ token
ElseIf parentKind = SyntaxKind.XmlElementAccessExpression OrElse
parentKind = SyntaxKind.XmlAttributeAccessExpression OrElse
parentKind = SyntaxKind.XmlDescendantAccessExpression Then
' Dev 10/11 do not allow a "." on a line after a ".",
' This is an error
' a = <x/>.
' ..<x>
'
' while this is allowed
' a = <x/>.
' @<x>
' Note, this restriction may not be necessary. See comment in ParseQualifiedExpr line 830.
If CType(token.Parent, XmlMemberAccessExpressionSyntax).Base IsNot Nothing Then
Return token.GetNextToken.Kind <> SyntaxKind.DotToken
Else
Return False
End If
Else
Return True
End If
' After the With keyword in a member initializer.
Case SyntaxKind.WithKeyword
Return parentKind = SyntaxKind.ObjectMemberInitializer
' Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).
' After the From keyword in a collection initializer.
Case SyntaxKind.AggregateKeyword,
SyntaxKind.ByKeyword,
SyntaxKind.EqualsKeyword,
SyntaxKind.FromKeyword,
SyntaxKind.IntoKeyword,
SyntaxKind.JoinKeyword,
SyntaxKind.WhereKeyword
Return True
' This is new in Roslyn.
Case SyntaxKind.GetXmlNamespaceKeyword,
SyntaxKind.OfKeyword
Return True
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.GroupKeyword
Return parentKind <> SyntaxKind.GroupJoinClause
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.SkipKeyword
Return parentKind <> SyntaxKind.SkipWhileClause
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.TakeKeyword
Return parentKind <> SyntaxKind.TakeWhileClause
' After the In keyword in a For Each statement.
Case SyntaxKind.InKeyword
Return parentKind = SyntaxKind.CollectionRangeVariable OrElse
parentKind = SyntaxKind.ForEachStatement
' Keywords that may appear outside of query clauses
Case SyntaxKind.OnKeyword,
SyntaxKind.LetKeyword,
SyntaxKind.SelectKeyword,
SyntaxKind.WhileKeyword
Return TypeOf token.Parent Is QueryClauseSyntax
' XML Literals
Case SyntaxKind.BeginCDataToken,
SyntaxKind.DoubleQuoteToken,
SyntaxKind.LessThanExclamationMinusMinusToken,
SyntaxKind.LessThanQuestionToken,
SyntaxKind.XmlKeyword,
SyntaxKind.XmlNameToken,
SyntaxKind.XmlTextLiteralToken
Return True
Case SyntaxKind.EndCDataToken,
SyntaxKind.MinusMinusGreaterThanToken,
SyntaxKind.QuestionGreaterThanToken,
SyntaxKind.SlashGreaterThanToken
' An implicit line continuation is allowed only if the token is not the end of
' the xml literal. Walk up the parent chain and see if there is a parent node
' whose end extends beyond this token.
Dim p As XmlNodeSyntax = Nothing
Dim n = TryCast(token.Parent.Parent, XmlNodeSyntax)
While n IsNot Nothing
p = n
If p.EndPosition > token.EndPosition Then
Return True
End If
n = TryCast(n.Parent, XmlNodeSyntax)
End While
Return False
Case SyntaxKind.ColonToken
Return parentKind = SyntaxKind.XmlPrefix
Case Else
Return False
End Select
End Function
''' <summary>
''' Indicates whether a newline may validly precede the specified SyntaxToken without requiring an explicit line continuation sequence ' _' or terminating the containing statement.
''' </summary>
''' <param name="token">The token to test. This token must be parented by a SyntaxNode.</param>
''' <returns>True if implicit line continuation is allowed after token.</returns>
''' <remarks>
''' <para>Refer to "Statements in Visual Basic", 2010 version, http://msdn.microsoft.com/en-us/library/865x40k4(v=vs.100).aspx
''' for examples.</para>
''' <para>Implicit line continuation may be used in Visual Basic: </para>
''' <list>
''' <item>After a comma (,).</item>
''' <item>After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.</item>
''' <item>After an open parenthesis (() or before a closing parenthesis ()).</item>
''' <item>After an open curly brace ({) or before a closing curly brace (}).</item>
''' <item>After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.</item>
''' <item>
''' <para>Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
''' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).</para>
''' <para>You cannot break a line between the keywords of query operators that are made up of multiple keywords
''' (Order By, Group Join, Take While, and Skip While).</para>
''' </item>
''' <item>After the concatenation operator (&).</item>
''' <item>After assignment operators (=, &=, :=, +=, -=, *=, /=, \=, ^=, <<=, >>=).</item>
''' <item>After binary operators (+, -, /, *, Mod, <>, <, >, <=, >=, ^, >>, <<, And, AndAlso, Or, OrElse, Like, Xor) within an expression.</item>
''' <item>After the Is and IsNot operators.</item>
''' <item>After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.</item>
''' <item>
''' <para>Also after a greater-than sign (>) when you specify an attribute.</para>
''' <para>However, you must include a line-continuation character (_) when you specify assembly-level or module-level attributes.</para>
''' </item>
''' <item>
''' <para>After a member qualifier character (.) and before the member name.</para>
''' <para>However, you must include a line-continuation character (_) following a member qualifier character when you are using the With statement or
''' supplying values in the initialization list for a type.</para>
''' </item>
''' <item>
''' <para>After an XML axis property qualifier (. or ...).</para>
''' <para>However, you must include a line-continuation character (_) when you specify a member qualifier when you are using the With keyword.</para>
''' </item>
''' <item>After the From keyword in a collection initializer.</item>
''' <item>After the With keyword in a member initializer.</item>
''' <item>After the In keyword in a For Each statement.</item>
''' </list>
''' </remarks>
Public Shared Function AllowsLeadingImplicitLineContinuation(token As SyntaxToken) As Boolean
If token.Parent Is Nothing Then Throw New ArgumentException("'token' must be parented by a SyntaxNode.")
Dim kind = token.Kind
Dim parentKind = token.Parent.Kind
' This list taken from: "Statements in Visual Basic", 2010 version, http://msdn.microsoft.com/en-us/library/865x40k4(v=vs.100).aspx
Select Case kind
' After a less-than sign (<) or before a greater-than sign (>) when you specify an attribute.
Case SyntaxKind.GreaterThanToken,
SyntaxKind.LessThanToken
Return parentKind = SyntaxKind.AttributeList
' After an open parenthesis (() or before a closing parenthesis ()).
' After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.
Case SyntaxKind.CloseParenToken,
SyntaxKind.PercentGreaterThanToken
Return True
' After an open curly brace ({) or before a closing curly brace (})
' However, a line-continuation character is required before the closing curly brace of a string interpolation.
Case SyntaxKind.CloseBraceToken
If parentKind = SyntaxKind.Interpolation Then
Return False
End If
Return True
' Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).
Case SyntaxKind.AscendingKeyword,
SyntaxKind.DescendingKeyword,
SyntaxKind.DistinctKeyword,
SyntaxKind.GroupKeyword,
SyntaxKind.IntoKeyword,
SyntaxKind.OrderKeyword,
SyntaxKind.SkipKeyword,
SyntaxKind.TakeKeyword,
SyntaxKind.WhereKeyword
Return True
' You cannot break a line between the keywords of query operators that are made up of multiple keywords
' (Order By, Group Join, Take While, and Skip While).
Case SyntaxKind.JoinKeyword
Return parentKind <> SyntaxKind.GroupJoinClause
' Keywords that may appear outside of query clauses
Case SyntaxKind.InKeyword,
SyntaxKind.LetKeyword,
SyntaxKind.OnKeyword,
SyntaxKind.SelectKeyword
Return TypeOf token.Parent Is QueryClauseSyntax
Case SyntaxKind.AggregateKeyword,
SyntaxKind.FromKeyword
' Allow a leading line continuation only if this is a QueryClause and it is not the first clause
' in a query expression.
Dim p As VisualBasicSyntaxNode = TryCast(token.Parent, QueryClauseSyntax)
If p Is Nothing Then
Return False
End If
p = p.Parent
While p IsNot Nothing
If TypeOf p Is QueryExpressionSyntax Then
If p.GetLocation.SourceSpan.Start < token.SpanStart Then
Return True
Else
Return False
End If
End If
p = p.Parent
End While
Return False
Case Else
Return False
End Select
End Function
Public Shared Function GetOperatorKind(operatorMetadataName As String) As SyntaxKind
Dim opInfo = OverloadResolution.GetOperatorInfo(operatorMetadataName)
Return If(opInfo.ParamCount = 0, SyntaxKind.None, OverloadResolution.GetOperatorTokenKind(opInfo))
End Function
Public Shared Function IsAccessibilityModifier(kind As SyntaxKind) As Boolean
Select Case kind
Case SyntaxKind.PrivateKeyword,
SyntaxKind.ProtectedKeyword,
SyntaxKind.FriendKeyword,
SyntaxKind.PublicKeyword
Return True
Case Else
Return False
End Select
End Function
Friend Shared Function IsTerminator(kind As SyntaxKind) As Boolean
Return kind = SyntaxKind.StatementTerminatorToken OrElse
kind = SyntaxKind.ColonToken OrElse
kind = SyntaxKind.EndOfFileToken
End Function
Friend Shared Function IsWithinPreprocessorConditionalExpression(node As SyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Dim parent = node.Parent
While parent IsNot Nothing
Select Case parent.Kind()
Case SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseIfDirectiveTrivia
Return DirectCast(parent, IfDirectiveTriviaSyntax).Condition Is node
Case SyntaxKind.ConstDirectiveTrivia
Return DirectCast(parent, ConstDirectiveTriviaSyntax).Value Is node
Case Else
node = parent
parent = node.Parent
End Select
End While
Return False
End Function
''' <summary>
''' Checks whether the element name is reserved.
'''
''' For example:
''' "Item3" is reserved.
''' "Rest", "ToString" and other members of System.ValueTuple are reserved.
''' Names that are not reserved return False.
''' </summary>
Public Shared Function IsReservedTupleElementName(elementName As String) As Boolean
Return TupleTypeSymbol.IsElementNameReserved(elementName) <> -1
End Function
End Class
End Namespace
|