/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Syntax/SyntaxFacts.vb
1 189 строк
56 KB
Cyrus Najmabadi
Make approved api changes
22 ноя 2024, 23:01
22 ноя 2024, 23:01
435ff12
Код
Авторство
О чём код?
' 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 NotInheritable 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