/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/SyntaxNodeExtensions.vb
1 307 строк
61 KB
Cyrus Najmabadi
Precursor to share code with RoslynAnalyzers. (#79117)
24 июн 2025, 05:11
Не верифицирован
24 июн 2025, 05:11
469f6d9
Код
Авторство
О чём код?
' 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.Collections.Immutable Imports System.Runtime.CompilerServices Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.LanguageService Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Friend Module SyntaxNodeExtensions <Extension()> Public Function IsParentKind(node As SyntaxNode, kind As SyntaxKind) As Boolean Return node IsNot Nothing AndAlso node.Parent.IsKind(kind) End Function <Extension()> Public Function IsParentKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind) As Boolean Return node IsNot Nothing AndAlso IsKind(node.Parent, kind1, kind2) End Function <Extension()> Public Function IsParentKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind) As Boolean Return node IsNot Nothing AndAlso IsKind(node.Parent, kind1, kind2, kind3) End Function <Extension()> Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind) As Boolean If node Is Nothing Then Return False End If Return node.Kind = kind1 OrElse node.Kind = kind2 End Function <Extension()> Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind) As Boolean If node Is Nothing Then Return False End If Return node.Kind = kind1 OrElse node.Kind = kind2 OrElse node.Kind = kind3 End Function <Extension()> Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind, kind4 As SyntaxKind) As Boolean If node Is Nothing Then Return False End If Return node.Kind = kind1 OrElse node.Kind = kind2 OrElse node.Kind = kind3 OrElse node.Kind = kind4 End Function <Extension()> Public Function IsKind(node As SyntaxNode, ParamArray kinds As SyntaxKind()) As Boolean If node Is Nothing Then Return False End If Return kinds.Contains(node.Kind()) End Function <Extension()> Public Function IsInConstantContext(expression As SyntaxNode) As Boolean If expression.GetAncestor(Of ParameterSyntax)() IsNot Nothing Then Return True End If ' TODO(cyrusn): Add more cases Return False End Function <Extension()> Public Function IsInStaticContext(node As SyntaxNode) As Boolean Dim containingType = node.GetAncestorOrThis(Of TypeBlockSyntax)() If containingType.IsKind(SyntaxKind.ModuleBlock) Then Return True End If Return node.GetAncestorsOrThis(Of StatementSyntax)(). SelectMany(Function(s) s.GetModifiers()). Any(Function(t) t.Kind = SyntaxKind.SharedKeyword) End Function <Extension()> Public Function IsStatementContainerNode(node As SyntaxNode) As Boolean If node.IsExecutableBlock() Then Return True End If Dim singleLineLambdaExpression = TryCast(node, SingleLineLambdaExpressionSyntax) If singleLineLambdaExpression IsNot Nothing AndAlso TypeOf singleLineLambdaExpression.Body Is ExecutableStatementSyntax Then Return True End If Return False End Function <Extension()> Public Function GetStatements(node As SyntaxNode) As SyntaxList(Of StatementSyntax) Contract.ThrowIfNull(node) Contract.ThrowIfFalse(node.IsStatementContainerNode()) Dim methodBlock = TryCast(node, MethodBlockBaseSyntax) If methodBlock IsNot Nothing Then Return methodBlock.Statements End If Dim whileBlock = TryCast(node, WhileBlockSyntax) If whileBlock IsNot Nothing Then Return whileBlock.Statements End If Dim usingBlock = TryCast(node, UsingBlockSyntax) If usingBlock IsNot Nothing Then Return usingBlock.Statements End If Dim syncLockBlock = TryCast(node, SyncLockBlockSyntax) If syncLockBlock IsNot Nothing Then Return syncLockBlock.Statements End If Dim withBlock = TryCast(node, WithBlockSyntax) If withBlock IsNot Nothing Then Return withBlock.Statements End If Dim singleLineIfStatement = TryCast(node, SingleLineIfStatementSyntax) If singleLineIfStatement IsNot Nothing Then Return singleLineIfStatement.Statements End If Dim singleLineElseClause = TryCast(node, SingleLineElseClauseSyntax) If singleLineElseClause IsNot Nothing Then Return singleLineElseClause.Statements End If Dim ifBlock = TryCast(node, MultiLineIfBlockSyntax) If ifBlock IsNot Nothing Then Return ifBlock.Statements End If Dim elseIfBlock = TryCast(node, ElseIfBlockSyntax) If elseIfBlock IsNot Nothing Then Return elseIfBlock.Statements End If Dim elseBlock = TryCast(node, ElseBlockSyntax) If elseBlock IsNot Nothing Then Return elseBlock.Statements End If Dim tryBlock = TryCast(node, TryBlockSyntax) If tryBlock IsNot Nothing Then Return tryBlock.Statements End If Dim catchBlock = TryCast(node, CatchBlockSyntax) If catchBlock IsNot Nothing Then Return catchBlock.Statements End If Dim finallyBlock = TryCast(node, FinallyBlockSyntax) If finallyBlock IsNot Nothing Then Return finallyBlock.Statements End If Dim caseBlock = TryCast(node, CaseBlockSyntax) If caseBlock IsNot Nothing Then Return caseBlock.Statements End If Dim doLoopBlock = TryCast(node, DoLoopBlockSyntax) If doLoopBlock IsNot Nothing Then Return doLoopBlock.Statements End If Dim forBlock = TryCast(node, ForOrForEachBlockSyntax) If forBlock IsNot Nothing Then Return forBlock.Statements End If Dim singleLineLambdaExpression = TryCast(node, SingleLineLambdaExpressionSyntax) If singleLineLambdaExpression IsNot Nothing Then Return If(TypeOf singleLineLambdaExpression.Body Is StatementSyntax, SyntaxFactory.SingletonList(DirectCast(singleLineLambdaExpression.Body, StatementSyntax)), Nothing) End If Dim multiLineLambdaExpression = TryCast(node, MultiLineLambdaExpressionSyntax) If multiLineLambdaExpression IsNot Nothing Then Return multiLineLambdaExpression.Statements End If Throw ExceptionUtilities.UnexpectedValue(node) End Function <Extension()> Friend Function IsAsyncSupportedFunctionSyntax(node As SyntaxNode) As Boolean Select Case node?.Kind() Case _ SyntaxKind.FunctionBlock, SyntaxKind.SubBlock, SyntaxKind.MultiLineFunctionLambdaExpression, SyntaxKind.MultiLineSubLambdaExpression, SyntaxKind.SingleLineFunctionLambdaExpression, SyntaxKind.SingleLineSubLambdaExpression Return True End Select Return False End Function <Extension()> Friend Function IsMultiLineLambda(node As SyntaxNode) As Boolean Return SyntaxFacts.IsMultiLineLambdaExpression(node.Kind()) End Function <Extension()> Friend Function GetTypeCharacterString(type As TypeCharacter) As String Select Case type Case TypeCharacter.Integer Return "%" Case TypeCharacter.Long Return "&" Case TypeCharacter.Decimal Return "@" Case TypeCharacter.Single Return "!" Case TypeCharacter.Double Return "#" Case TypeCharacter.String Return "$" Case Else Throw New ArgumentException("Unexpected TypeCharacter.", NameOf(type)) End Select End Function <Extension()> Public Function SpansPreprocessorDirective(Of TSyntaxNode As SyntaxNode)(list As IEnumerable(Of TSyntaxNode)) As Boolean Return VisualBasicSyntaxFacts.Instance.SpansPreprocessorDirective(list) End Function <Extension()> Public Function ConvertToSingleLine(Of TNode As SyntaxNode)(node As TNode, Optional useElasticTrivia As Boolean = False) As TNode If node Is Nothing Then Return node End If Dim rewriter = New SingleLineRewriter(useElasticTrivia) Return DirectCast(rewriter.Visit(node), TNode) End Function ''' <summary> ''' Breaks up the list of provided nodes, based on how they are ''' interspersed with pp directives, into groups. Within these groups ''' nodes can be moved around safely, without breaking any pp ''' constructs. ''' </summary> <Extension()> Public Function SplitNodesOnPreprocessorBoundaries(Of TSyntaxNode As SyntaxNode)( nodes As IEnumerable(Of TSyntaxNode), cancellationToken As CancellationToken) As IList(Of IList(Of TSyntaxNode)) Dim result = New List(Of IList(Of TSyntaxNode))() Dim currentGroup = New List(Of TSyntaxNode)() For Each node In nodes Dim hasUnmatchedInteriorDirective = node.ContainsInterleavedDirective(cancellationToken) Dim hasLeadingDirective = node.GetLeadingTrivia().Any(Function(t) SyntaxFacts.IsPreprocessorDirective(t.Kind)) If hasUnmatchedInteriorDirective Then ' we have a #if/#endif/#region/#endregion/#else/#elif in ' this node that belongs to a span of pp directives that ' is not entirely contained within the node. i.e.: ' ' void Goo() { ' #if ... ' } ' ' This node cannot be moved at all. It is in a group that ' only contains itself (and thus can never be moved). ' add whatever group we've built up to now. And reset the ' next group to empty. result.Add(currentGroup) currentGroup = New List(Of TSyntaxNode)() result.Add(New List(Of TSyntaxNode) From {node}) ElseIf hasLeadingDirective Then ' We have a PP directive before us. i.e.: ' ' #if ... ' void Goo() { ' ' That means we start a new group that is contained between ' the above directive and the following directive. ' add whatever group we've built up to now. And reset the ' next group to empty. result.Add(currentGroup) currentGroup = New List(Of TSyntaxNode)() currentGroup.Add(node) Else ' simple case. just add ourselves to the current group currentGroup.Add(node) End If Next ' add the remainder of the final group. result.Add(currentGroup) ' Now, filter out any empty groups. result = result.Where(Function(group) Not group.IsEmpty()).ToList() Return result End Function ''' <summary> ''' Returns true if the passed in node contains an interleaved pp ''' directive. ''' ''' i.e. The following returns false: ''' ''' void Goo() { ''' #if true ''' #endif ''' } ''' ''' #if true ''' void Goo() { ''' } ''' #endif ''' ''' but these return true: ''' ''' #if true ''' void Goo() { ''' #endif ''' } ''' ''' void Goo() { ''' #if true ''' } ''' #endif ''' ''' #if true ''' void Goo() { ''' #else ''' } ''' #endif ''' ''' i.e. the method returns true if it contains a PP directive that ''' belongs to a grouping constructs (like #if/#endif or ''' #region/#endregion), but the grouping construct isn't entirely c ''' contained within the span of the node. ''' </summary> <Extension()> Public Function ContainsInterleavedDirective(node As SyntaxNode, cancellationToken As CancellationToken) As Boolean Return VisualBasicSyntaxFacts.Instance.ContainsInterleavedDirective(node, cancellationToken) End Function <Extension> Public Function ContainsInterleavedDirective( token As SyntaxToken, textSpan As TextSpan, cancellationToken As CancellationToken) As Boolean Return ContainsInterleavedDirective(textSpan, token.LeadingTrivia, cancellationToken) OrElse ContainsInterleavedDirective(textSpan, token.TrailingTrivia, cancellationToken) End Function Private Function ContainsInterleavedDirective( textSpan As TextSpan, list As SyntaxTriviaList, cancellationToken As CancellationToken) As Boolean For Each trivia In list If textSpan.Contains(trivia.Span) Then If ContainsInterleavedDirective(textSpan, trivia, cancellationToken) Then Return True End If End If Next trivia Return False End Function Private Function ContainsInterleavedDirective( textSpan As TextSpan, trivia As SyntaxTrivia, cancellationToken As CancellationToken) As Boolean If trivia.HasStructure AndAlso TypeOf trivia.GetStructure() Is DirectiveTriviaSyntax Then Dim parentSpan = trivia.GetStructure().Span Dim directiveSyntax = DirectCast(trivia.GetStructure(), DirectiveTriviaSyntax) If directiveSyntax.IsKind(SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia, SyntaxKind.IfDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia) Then Dim match = directiveSyntax.GetMatchingStartOrEndDirective(cancellationToken) If match IsNot Nothing Then Dim matchSpan = match.Span If Not textSpan.Contains(matchSpan.Start) Then ' The match for this pp directive is outside ' this node. Return True End If End If ElseIf directiveSyntax.IsKind(SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ElseIfDirectiveTrivia) Then Dim directives = directiveSyntax.GetMatchingConditionalDirectives(cancellationToken) If directives.Any() Then If Not textSpan.Contains(directives(0).SpanStart) OrElse Not textSpan.Contains(directives.Last().SpanStart) Then ' This else/elif belongs to a pp span that isn't ' entirely within this node. Return True End If End If End If End If Return False End Function <Extension()> Public Function GetLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As ImmutableArray(Of SyntaxTrivia) Return VisualBasicFileBannerFacts.Instance.GetLeadingBlankLines(node) End Function <Extension()> Public Function GetNodeWithoutLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As TSyntaxNode Return VisualBasicFileBannerFacts.Instance.GetNodeWithoutLeadingBlankLines(node) End Function <Extension()> Public Function GetNodeWithoutLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode, ByRef strippedTrivia As ImmutableArray(Of SyntaxTrivia)) As TSyntaxNode Return VisualBasicFileBannerFacts.Instance.GetNodeWithoutLeadingBlankLines(node, strippedTrivia) End Function <Extension()> Public Function GetLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As ImmutableArray(Of SyntaxTrivia) Return VisualBasicFileBannerFacts.Instance.GetLeadingBannerAndPreprocessorDirectives(node) End Function <Extension()> Public Function GetNodeWithoutLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As TSyntaxNode Return VisualBasicFileBannerFacts.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node) End Function <Extension()> Public Function GetNodeWithoutLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode, ByRef strippedTrivia As ImmutableArray(Of SyntaxTrivia)) As TSyntaxNode Return VisualBasicFileBannerFacts.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, strippedTrivia) End Function ''' <summary> ''' Returns true if this is a block that can contain multiple executable statements. i.e. ''' this node is the VB equivalent of a BlockSyntax in C#. ''' </summary> <Extension()> Public Function IsExecutableBlock(node As SyntaxNode) As Boolean If node IsNot Nothing Then If TypeOf node Is MethodBlockBaseSyntax OrElse TypeOf node Is DoLoopBlockSyntax OrElse TypeOf node Is ForOrForEachBlockSyntax OrElse TypeOf node Is MultiLineLambdaExpressionSyntax Then Return True End If Select Case node.Kind Case SyntaxKind.WhileBlock, SyntaxKind.UsingBlock, SyntaxKind.SyncLockBlock, SyntaxKind.WithBlock, SyntaxKind.SingleLineIfStatement, SyntaxKind.SingleLineElseClause, SyntaxKind.SingleLineSubLambdaExpression, SyntaxKind.MultiLineIfBlock, SyntaxKind.ElseIfBlock, SyntaxKind.ElseBlock, SyntaxKind.TryBlock, SyntaxKind.CatchBlock, SyntaxKind.FinallyBlock, SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock Return True End Select End If Return False End Function <Extension()> Public Function GetContainingExecutableBlocks(node As SyntaxNode) As IEnumerable(Of SyntaxNode) Return node.GetAncestorsOrThis(Of StatementSyntax). Where(Function(s) s.Parent.IsExecutableBlock() AndAlso s.Parent.GetExecutableBlockStatements().Contains(s)). Select(Function(s) s.Parent) End Function <Extension()> Public Function GetContainingMultiLineExecutableBlocks(node As SyntaxNode) As IEnumerable(Of SyntaxNode) Return node.GetAncestorsOrThis(Of StatementSyntax). Where(Function(s) s.Parent.IsMultiLineExecutableBlock AndAlso s.Parent.GetExecutableBlockStatements().Contains(s)). Select(Function(s) s.Parent) End Function <Extension()> Public Function FindInnermostCommonExecutableBlock(nodes As IEnumerable(Of SyntaxNode)) As SyntaxNode Dim blocks As IEnumerable(Of SyntaxNode) = Nothing For Each node In nodes blocks = If(blocks Is Nothing, node.GetContainingExecutableBlocks(), blocks.Intersect(node.GetContainingExecutableBlocks())) Next Return If(blocks Is Nothing, Nothing, blocks.FirstOrDefault()) End Function <Extension()> Public Function GetExecutableBlockStatements(node As SyntaxNode) As SyntaxList(Of StatementSyntax) If node IsNot Nothing Then If TypeOf node Is MethodBlockBaseSyntax Then Return DirectCast(node, MethodBlockBaseSyntax).Statements ElseIf TypeOf node Is DoLoopBlockSyntax Then Return DirectCast(node, DoLoopBlockSyntax).Statements ElseIf TypeOf node Is ForOrForEachBlockSyntax Then Return DirectCast(node, ForOrForEachBlockSyntax).Statements ElseIf TypeOf node Is MultiLineLambdaExpressionSyntax Then Return DirectCast(node, MultiLineLambdaExpressionSyntax).Statements End If Select Case node.Kind Case SyntaxKind.WhileBlock Return DirectCast(node, WhileBlockSyntax).Statements Case SyntaxKind.UsingBlock Return DirectCast(node, UsingBlockSyntax).Statements Case SyntaxKind.SyncLockBlock Return DirectCast(node, SyncLockBlockSyntax).Statements Case SyntaxKind.WithBlock Return DirectCast(node, WithBlockSyntax).Statements Case SyntaxKind.SingleLineIfStatement Return DirectCast(node, SingleLineIfStatementSyntax).Statements Case SyntaxKind.SingleLineElseClause Return DirectCast(node, SingleLineElseClauseSyntax).Statements Case SyntaxKind.SingleLineSubLambdaExpression Return SyntaxFactory.SingletonList(DirectCast(DirectCast(node, SingleLineLambdaExpressionSyntax).Body, StatementSyntax)) Case SyntaxKind.MultiLineIfBlock Return DirectCast(node, MultiLineIfBlockSyntax).Statements Case SyntaxKind.ElseIfBlock Return DirectCast(node, ElseIfBlockSyntax).Statements Case SyntaxKind.ElseBlock Return DirectCast(node, ElseBlockSyntax).Statements Case SyntaxKind.TryBlock Return DirectCast(node, TryBlockSyntax).Statements Case SyntaxKind.CatchBlock Return DirectCast(node, CatchBlockSyntax).Statements Case SyntaxKind.FinallyBlock Return DirectCast(node, FinallyBlockSyntax).Statements Case SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock Return DirectCast(node, CaseBlockSyntax).Statements End Select End If Return Nothing End Function <Extension()> Public Function ReplaceStatements(node As SyntaxNode, statements As SyntaxList(Of StatementSyntax), ParamArray annotations As SyntaxAnnotation()) As SyntaxNode Return node.TypeSwitch( Function(x As MethodBlockSyntax) x.WithStatements(statements), Function(x As ConstructorBlockSyntax) x.WithStatements(statements), Function(x As OperatorBlockSyntax) x.WithStatements(statements), Function(x As AccessorBlockSyntax) x.WithStatements(statements), Function(x As DoLoopBlockSyntax) x.WithStatements(statements), Function(x As ForBlockSyntax) x.WithStatements(statements), Function(x As ForEachBlockSyntax) x.WithStatements(statements), Function(x As MultiLineLambdaExpressionSyntax) x.WithStatements(statements), Function(x As WhileBlockSyntax) x.WithStatements(statements), Function(x As UsingBlockSyntax) x.WithStatements(statements), Function(x As SyncLockBlockSyntax) x.WithStatements(statements), Function(x As WithBlockSyntax) x.WithStatements(statements), Function(x As SingleLineIfStatementSyntax) x.WithStatements(statements), Function(x As SingleLineElseClauseSyntax) x.WithStatements(statements), Function(x As SingleLineLambdaExpressionSyntax) ReplaceSingleLineLambdaExpressionStatements(x, statements, annotations), Function(x As MultiLineIfBlockSyntax) x.WithStatements(statements), Function(x As ElseIfBlockSyntax) x.WithStatements(statements), Function(x As ElseBlockSyntax) x.WithStatements(statements), Function(x As TryBlockSyntax) x.WithStatements(statements), Function(x As CatchBlockSyntax) x.WithStatements(statements), Function(x As FinallyBlockSyntax) x.WithStatements(statements), Function(x As CaseBlockSyntax) x.WithStatements(statements)) End Function <Extension()> Public Function ReplaceSingleLineLambdaExpressionStatements( node As SingleLineLambdaExpressionSyntax, statements As SyntaxList(Of StatementSyntax), ParamArray annotations As SyntaxAnnotation()) As SyntaxNode If node.Kind = SyntaxKind.SingleLineSubLambdaExpression Then Dim singleLineLambda = DirectCast(node, SingleLineLambdaExpressionSyntax) If statements.Count = 1 Then Return node.WithBody(statements.First()) Else #If False Then Dim statementsAndSeparators = statements.GetWithSeparators() If statementsAndSeparators.LastOrDefault().IsNode Then statements = Syntax.SeparatedList(Of StatementSyntax)( statementsAndSeparators.Concat(Syntax.Token(SyntaxKind.StatementTerminatorToken))) End If #End If Return SyntaxFactory.MultiLineSubLambdaExpression( singleLineLambda.SubOrFunctionHeader, statements, SyntaxFactory.EndSubStatement()).WithAdditionalAnnotations(annotations) End If End If ' Can't be called on a single line lambda (as it can't have statements for children) Throw New InvalidOperationException() End Function <Extension()> Public Function ReplaceStatements(tree As SyntaxTree, executableBlock As SyntaxNode, statements As SyntaxList(Of StatementSyntax), ParamArray annotations As SyntaxAnnotation()) As SyntaxNode If executableBlock.IsSingleLineExecutableBlock() Then Return ConvertSingleLineToMultiLineExecutableBlock(tree, executableBlock, statements, annotations) End If ' TODO(cyrusn): Implement this. Throw ExceptionUtilities.Unreachable End Function <Extension()> Public Function IsSingleLineExecutableBlock(executableBlock As SyntaxNode) As Boolean Select Case executableBlock.Kind Case SyntaxKind.SingleLineElseClause, SyntaxKind.SingleLineIfStatement, SyntaxKind.SingleLineSubLambdaExpression Return executableBlock.GetExecutableBlockStatements().Count = 1 Case Else Return False End Select End Function <Extension()> Public Function IsMultiLineExecutableBlock(node As SyntaxNode) As Boolean Return node.IsExecutableBlock AndAlso Not node.IsSingleLineExecutableBlock End Function Private Sub UpdateStatements(executableBlock As SyntaxNode, newStatements As SyntaxList(Of StatementSyntax), annotations As SyntaxAnnotation(), ByRef singleLineIf As SingleLineIfStatementSyntax, ByRef multiLineIf As MultiLineIfBlockSyntax) Dim ifStatements As SyntaxList(Of StatementSyntax) Dim elseStatements As SyntaxList(Of StatementSyntax) Select Case executableBlock.Kind Case SyntaxKind.SingleLineIfStatement singleLineIf = DirectCast(executableBlock, SingleLineIfStatementSyntax) ifStatements = newStatements elseStatements = If(singleLineIf.ElseClause Is Nothing, Nothing, singleLineIf.ElseClause.Statements) Case SyntaxKind.SingleLineElseClause singleLineIf = DirectCast(executableBlock.Parent, SingleLineIfStatementSyntax) ifStatements = singleLineIf.Statements elseStatements = newStatements Case Else Return End Select Dim ifStatement = SyntaxFactory.IfStatement(singleLineIf.IfKeyword, singleLineIf.Condition, singleLineIf.ThenKeyword) _ .WithPrependedLeadingTrivia(SyntaxFactory.ElasticMarker).WithAppendedTrailingTrivia(SyntaxFactory.ElasticMarker) Dim elseBlockOpt = If(singleLineIf.ElseClause Is Nothing, Nothing, SyntaxFactory.ElseBlock( SyntaxFactory.ElseStatement(singleLineIf.ElseClause.ElseKeyword).WithAppendedTrailingTrivia(SyntaxFactory.ElasticMarker), elseStatements) _ .WithPrependedLeadingTrivia(SyntaxFactory.ElasticMarker).WithAppendedTrailingTrivia(SyntaxFactory.ElasticMarker)) Dim [endIf] = SyntaxFactory.EndIfStatement(SyntaxFactory.Token(SyntaxKind.EndKeyword), SyntaxFactory.Token(SyntaxKind.IfKeyword)) _ .WithAdditionalAnnotations(annotations) multiLineIf = SyntaxFactory.MultiLineIfBlock( SyntaxFactory.IfStatement(singleLineIf.IfKeyword, singleLineIf.Condition, singleLineIf.ThenKeyword) _ .WithPrependedLeadingTrivia(SyntaxFactory.ElasticMarker).WithAppendedTrailingTrivia(SyntaxFactory.ElasticMarker), ifStatements, Nothing, elseBlockOpt, [endIf]) _ .WithAdditionalAnnotations(annotations) End Sub <Extension()> Public Function ConvertSingleLineToMultiLineExecutableBlock( tree As SyntaxTree, block As SyntaxNode, statements As SyntaxList(Of StatementSyntax), ParamArray annotations As SyntaxAnnotation()) As SyntaxNode Dim oldBlock = block Dim newBlock = block Dim current = block While current.IsSingleLineExecutableBlock() If current.Kind = SyntaxKind.SingleLineIfStatement OrElse current.Kind = SyntaxKind.SingleLineElseClause Then Dim singleLineIf As SingleLineIfStatementSyntax = Nothing Dim multiLineIf As MultiLineIfBlockSyntax = Nothing UpdateStatements(current, statements, annotations, singleLineIf, multiLineIf) statements = SyntaxFactory.List({DirectCast(multiLineIf, StatementSyntax)}) current = singleLineIf.Parent oldBlock = singleLineIf newBlock = multiLineIf ElseIf current.Kind = SyntaxKind.SingleLineSubLambdaExpression Then Dim singleLineLambda = DirectCast(current, SingleLineLambdaExpressionSyntax) Dim multiLineLambda = SyntaxFactory.MultiLineSubLambdaExpression( singleLineLambda.SubOrFunctionHeader, statements, SyntaxFactory.EndSubStatement()).WithAdditionalAnnotations(annotations) oldBlock = singleLineLambda newBlock = multiLineLambda Exit While Else Exit While End If End While Return tree.GetRoot().ReplaceNode(oldBlock, newBlock) End Function <Extension()> Public Function GetBraces(node As SyntaxNode) As (openBrace As SyntaxToken, closeBrace As SyntaxToken) Return node.TypeSwitch( Function(n As TypeParameterMultipleConstraintClauseSyntax) (n.OpenBraceToken, n.CloseBraceToken), Function(n As ObjectMemberInitializerSyntax) (n.OpenBraceToken, n.CloseBraceToken), Function(n As CollectionInitializerSyntax) (n.OpenBraceToken, n.CloseBraceToken), Function(n As SyntaxNode) CType(Nothing, (SyntaxToken, SyntaxToken))) End Function <Extension()> Public Function GetParentheses(node As SyntaxNode) As ValueTuple(Of SyntaxToken, SyntaxToken) Return node.TypeSwitch( Function(n As TypeParameterListSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As ParameterListSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As ArrayRankSpecifierSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As ParenthesizedExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As GetTypeExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As GetXmlNamespaceExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As CTypeExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As DirectCastExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As TryCastExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As PredefinedCastExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As BinaryConditionalExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As TernaryConditionalExpressionSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As ArgumentListSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As FunctionAggregationSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As TypeArgumentListSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As ExternalSourceDirectiveTriviaSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As ExternalChecksumDirectiveTriviaSyntax) (n.OpenParenToken, n.CloseParenToken), Function(n As SyntaxNode) CType(Nothing, (SyntaxToken, SyntaxToken))) End Function <Extension> Public Function IsLeftSideOfSimpleAssignmentStatement(node As SyntaxNode) As Boolean Return node.IsParentKind(SyntaxKind.SimpleAssignmentStatement) AndAlso DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node End Function <Extension> Public Function IsLeftSideOfAnyAssignmentStatement(node As SyntaxNode) As Boolean Return node IsNot Nothing AndAlso node.Parent.IsAnyAssignmentStatement() AndAlso DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node End Function <Extension> Public Function IsAnyAssignmentStatement(node As SyntaxNode) As Boolean Return node IsNot Nothing AndAlso SyntaxFacts.IsAssignmentStatement(node.Kind) End Function <Extension> Public Function IsLeftSideOfCompoundAssignmentStatement(node As SyntaxNode) As Boolean Return node IsNot Nothing AndAlso node.Parent.IsCompoundAssignmentStatement() AndAlso DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node End Function <Extension> Public Function IsCompoundAssignmentStatement(node As SyntaxNode) As Boolean If node IsNot Nothing Then Select Case node.Kind Case SyntaxKind.AddAssignmentStatement, SyntaxKind.SubtractAssignmentStatement, SyntaxKind.MultiplyAssignmentStatement, SyntaxKind.DivideAssignmentStatement, SyntaxKind.IntegerDivideAssignmentStatement, SyntaxKind.ExponentiateAssignmentStatement, SyntaxKind.LeftShiftAssignmentStatement, SyntaxKind.RightShiftAssignmentStatement, SyntaxKind.ConcatenateAssignmentStatement Return True End Select End If Return False End Function <Extension> Public Function ParentingNodeContainsDiagnostics(node As SyntaxNode) As Boolean Dim topMostStatement = node _ .AncestorsAndSelf() _ .OfType(Of ExecutableStatementSyntax) _ .LastOrDefault() If topMostStatement IsNot Nothing Then Return topMostStatement.ContainsDiagnostics End If Dim topMostExpression = node _ .AncestorsAndSelf() _ .TakeWhile(Function(n) TypeOf n IsNot StatementSyntax) _ .OfType(Of ExpressionSyntax) _ .LastOrDefault() If topMostExpression.Parent IsNot Nothing Then Return topMostExpression.Parent.ContainsDiagnostics End If Return False End Function <Extension()> Public Function CheckTopLevel(node As SyntaxNode, span As TextSpan) As Boolean Dim block = TryCast(node, MethodBlockBaseSyntax) If block IsNot Nothing AndAlso block.ContainsInMethodBlockBody(span) Then Return True End If Dim field = TryCast(node, FieldDeclarationSyntax) If field IsNot Nothing Then For Each declaration In field.Declarators If declaration.Initializer IsNot Nothing AndAlso declaration.Initializer.Span.Contains(span) Then Return True End If Next End If Dim [property] = TryCast(node, PropertyStatementSyntax) If [property] IsNot Nothing AndAlso [property].Initializer IsNot Nothing AndAlso [property].Initializer.Span.Contains(span) Then Return True End If Return False End Function <Extension()> Public Function ContainsInMethodBlockBody(block As MethodBlockBaseSyntax, textSpan As TextSpan) As Boolean If block Is Nothing Then Return False End If Dim blockSpan = TextSpan.FromBounds(block.BlockStatement.Span.End, block.EndBlockStatement.SpanStart) Return blockSpan.Contains(textSpan) End Function <Extension()> Public Function GetMembers(node As SyntaxNode) As SyntaxList(Of StatementSyntax) Dim compilation = TryCast(node, CompilationUnitSyntax) If compilation IsNot Nothing Then Return compilation.Members End If Dim [namespace] = TryCast(node, NamespaceBlockSyntax) If [namespace] IsNot Nothing Then Return [namespace].Members End If Dim type = TryCast(node, TypeBlockSyntax) If type IsNot Nothing Then Return type.Members End If Dim [enum] = TryCast(node, EnumBlockSyntax) If [enum] IsNot Nothing Then Return [enum].Members End If Return Nothing End Function <Extension()> Public Function GetBodies(node As SyntaxNode) As IEnumerable(Of SyntaxNode) Dim method = TryCast(node, MethodBlockBaseSyntax) If method IsNot Nothing Then Return method.Statements End If Dim [event] = TryCast(node, EventBlockSyntax) If [event] IsNot Nothing Then Return [event].Accessors.SelectMany(Function(a) a.Statements) End If Dim [property] = TryCast(node, PropertyBlockSyntax) If [property] IsNot Nothing Then Return [property].Accessors.SelectMany(Function(a) a.Statements) End If Dim field = TryCast(node, FieldDeclarationSyntax) If field IsNot Nothing Then Return field.Declarators.Where(Function(d) d.Initializer IsNot Nothing).Select(Function(d) d.Initializer.Value).WhereNotNull() End If Dim initializer As EqualsValueSyntax = Nothing Dim [enum] = TryCast(node, EnumMemberDeclarationSyntax) If [enum] IsNot Nothing Then initializer = [enum].Initializer End If Dim propStatement = TryCast(node, PropertyStatementSyntax) If propStatement IsNot Nothing Then initializer = propStatement.Initializer End If If initializer IsNot Nothing AndAlso initializer.Value IsNot Nothing Then Return SpecializedCollections.SingletonEnumerable(initializer.Value) End If Return SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() End Function <Extension()> Public Iterator Function GetAliasImportsClauses(root As CompilationUnitSyntax) As IEnumerable(Of SimpleImportsClauseSyntax) For i = 0 To root.Imports.Count - 1 Dim statement = root.Imports(i) For j = 0 To statement.ImportsClauses.Count - 1 Dim importsClause = statement.ImportsClauses(j) If importsClause.Kind = SyntaxKind.SimpleImportsClause Then Dim simpleImportsClause = DirectCast(importsClause, SimpleImportsClauseSyntax) If simpleImportsClause.Alias IsNot Nothing Then Yield simpleImportsClause End If End If Next Next End Function <Extension> Friend Function GetParentConditionalAccessExpression(node As ExpressionSyntax) As ConditionalAccessExpressionSyntax ' Walk upwards based on the grammar/parser rules around ?. expressions (can be seen in ' ParseExpression.vb (.ParsePostFixExpression). ' ' These are the parts of the expression that the ?... expression can end with. Specifically ' ' 1. x?.y.M() // invocation ' 2. x?.y and x?.y.z // member access (covered under MemberAccessExpressionSyntax below) ' 3. x?!y // dictionary access (covered under MemberAccessExpressionSyntax below) ' 4. x?.y<...> // xml access If node.IsAnyMemberAccessExpressionName() Then node = DirectCast(node.Parent, ExpressionSyntax) End If ' Effectively, if we're on the RHS of the ? we have to walk up the RHS spine first until we hit the first ' conditional access. While (TypeOf node Is InvocationExpressionSyntax OrElse TypeOf node Is MemberAccessExpressionSyntax OrElse TypeOf node Is XmlMemberAccessExpressionSyntax) AndAlso TypeOf node.Parent IsNot ConditionalAccessExpressionSyntax node = TryCast(node.Parent, ExpressionSyntax) End While ' Two cases we have to care about ' ' 1. a?.b.$$c.d And ' 2. a?.b.$$c.d?.e... ' ' Note that `a?.b.$$c.d?.e.f?.g.h.i` falls into the same bucket as two. i.e. the parts after `.e` are ' lower in the tree And are Not seen as we walk upwards. ' ' ' To get the root ?. (the one after the `a`) we have to potentially consume the first ?. on the RHS of the ' right spine (i.e. the one after `d`). Once we do this, we then see if that itself Is on the RHS of a ' another conditional, And if so we hten return the one on the left. i.e. for '2' this goes in this direction: ' ' a?.b.$$c.d?.e // it will do: ' -----> ' <--------- ' ' Note that this only one CAE consumption on both sides. GetRootConditionalAccessExpression can be used to ' get the root parent in a case Like: ' ' x?.y?.z?.a?.b.$$c.d?.e.f?.g.h.i // It will do: ' -----> ' <--------- ' <--- ' <--- ' <--- If TypeOf node?.Parent Is ConditionalAccessExpressionSyntax AndAlso DirectCast(node.Parent, ConditionalAccessExpressionSyntax).Expression Is node Then node = DirectCast(node.Parent, ExpressionSyntax) End If If TypeOf node?.Parent Is ConditionalAccessExpressionSyntax AndAlso DirectCast(node.Parent, ConditionalAccessExpressionSyntax).WhenNotNull Is node Then node = DirectCast(node.Parent, ExpressionSyntax) End If Return TryCast(node, ConditionalAccessExpressionSyntax) End Function <Extension> Friend Function GetRootConditionalAccessExpression(node As ExpressionSyntax) As ConditionalAccessExpressionSyntax ' Once we've walked up the entire RHS, now we continually walk up the conditional accesses until we're at ' the root. For example, if we have `a?.b` And we're on the `.b`, this will give `a?.b`. Similarly with ' `a?.b?.c` if we're on either `.b` or `.c` this will result in `a?.b?.c` (i.e. the root of this CAE ' sequence). node = node.GetParentConditionalAccessExpression() While TypeOf node?.Parent Is ConditionalAccessExpressionSyntax Dim conditionalParent = DirectCast(node.Parent, ConditionalAccessExpressionSyntax) If conditionalParent.WhenNotNull Is node Then node = conditionalParent Else Exit While End If End While Return TryCast(node, ConditionalAccessExpressionSyntax) End Function <Extension> Public Function IsInExpressionTree(node As SyntaxNode, semanticModel As SemanticModel, expressionTypeOpt As INamedTypeSymbol, cancellationToken As CancellationToken) As Boolean If expressionTypeOpt IsNot Nothing Then Dim current = node While current IsNot Nothing If SyntaxFacts.IsSingleLineLambdaExpression(current.Kind) OrElse SyntaxFacts.IsMultiLineLambdaExpression(current.Kind) Then Dim typeInfo = semanticModel.GetTypeInfo(current, cancellationToken) If expressionTypeOpt.Equals(typeInfo.ConvertedType?.OriginalDefinition) Then Return True End If ElseIf TypeOf current Is OrderingSyntax OrElse TypeOf current Is QueryClauseSyntax OrElse TypeOf current Is FunctionAggregationSyntax OrElse TypeOf current Is ExpressionRangeVariableSyntax Then Dim info = semanticModel.GetSymbolInfo(current, cancellationToken) For Each symbol In info.GetAllSymbols() Dim method = TryCast(symbol, IMethodSymbol) If method IsNot Nothing AndAlso method.Parameters.Length > 0 AndAlso expressionTypeOpt.Equals(method.Parameters(0).Type.OriginalDefinition) Then Return True End If Next End If current = current.Parent End While End If Return False End Function <Extension> Public Function GetParameterList(declaration As SyntaxNode) As ParameterListSyntax Select Case declaration.Kind Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock Return DirectCast(declaration, MethodBlockSyntax).BlockStatement.ParameterList Case SyntaxKind.ConstructorBlock Return DirectCast(declaration, ConstructorBlockSyntax).BlockStatement.ParameterList Case SyntaxKind.OperatorBlock Return DirectCast(declaration, OperatorBlockSyntax).BlockStatement.ParameterList Case SyntaxKind.SubStatement, SyntaxKind.FunctionStatement Return DirectCast(declaration, MethodStatementSyntax).ParameterList Case SyntaxKind.SubNewStatement Return DirectCast(declaration, SubNewStatementSyntax).ParameterList Case SyntaxKind.OperatorStatement Return DirectCast(declaration, OperatorStatementSyntax).ParameterList Case SyntaxKind.DeclareSubStatement, SyntaxKind.DeclareFunctionStatement Return DirectCast(declaration, DeclareStatementSyntax).ParameterList Case SyntaxKind.DelegateSubStatement, SyntaxKind.DelegateFunctionStatement Return DirectCast(declaration, DelegateStatementSyntax).ParameterList Case SyntaxKind.PropertyBlock Return DirectCast(declaration, PropertyBlockSyntax).PropertyStatement.ParameterList Case SyntaxKind.PropertyStatement Return DirectCast(declaration, PropertyStatementSyntax).ParameterList Case SyntaxKind.EventBlock Return DirectCast(declaration, EventBlockSyntax).EventStatement.ParameterList Case SyntaxKind.EventStatement Return DirectCast(declaration, EventStatementSyntax).ParameterList Case SyntaxKind.MultiLineFunctionLambdaExpression, SyntaxKind.MultiLineSubLambdaExpression Return DirectCast(declaration, MultiLineLambdaExpressionSyntax).SubOrFunctionHeader.ParameterList Case SyntaxKind.SingleLineFunctionLambdaExpression, SyntaxKind.SingleLineSubLambdaExpression Return DirectCast(declaration, SingleLineLambdaExpressionSyntax).SubOrFunctionHeader.ParameterList Case Else Return Nothing End Select End Function <Extension> Public Function GetAttributeLists(node As SyntaxNode) As SyntaxList(Of AttributeListSyntax) Select Case node.Kind Case SyntaxKind.CompilationUnit Return SyntaxFactory.List(DirectCast(node, CompilationUnitSyntax).Attributes.SelectMany(Function(s) s.AttributeLists)) Case SyntaxKind.ClassBlock Return DirectCast(node, ClassBlockSyntax).BlockStatement.AttributeLists Case SyntaxKind.ClassStatement Return DirectCast(node, ClassStatementSyntax).AttributeLists Case SyntaxKind.StructureBlock Return DirectCast(node, StructureBlockSyntax).BlockStatement.AttributeLists Case SyntaxKind.StructureStatement Return DirectCast(node, StructureStatementSyntax).AttributeLists Case SyntaxKind.InterfaceBlock Return DirectCast(node, InterfaceBlockSyntax).BlockStatement.AttributeLists Case SyntaxKind.InterfaceStatement Return DirectCast(node, InterfaceStatementSyntax).AttributeLists Case SyntaxKind.EnumBlock Return DirectCast(node, EnumBlockSyntax).EnumStatement.AttributeLists Case SyntaxKind.EnumStatement Return DirectCast(node, EnumStatementSyntax).AttributeLists Case SyntaxKind.EnumMemberDeclaration Return DirectCast(node, EnumMemberDeclarationSyntax).AttributeLists Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement Return DirectCast(node, DelegateStatementSyntax).AttributeLists Case SyntaxKind.FieldDeclaration Return DirectCast(node, FieldDeclarationSyntax).AttributeLists Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock, SyntaxKind.ConstructorBlock Return DirectCast(node, MethodBlockBaseSyntax).BlockStatement.AttributeLists Case SyntaxKind.FunctionStatement, SyntaxKind.SubStatement Return DirectCast(node, MethodStatementSyntax).AttributeLists Case SyntaxKind.SubNewStatement Return DirectCast(node, SubNewStatementSyntax).AttributeLists Case SyntaxKind.Parameter Return DirectCast(node, ParameterSyntax).AttributeLists Case SyntaxKind.PropertyBlock Return DirectCast(node, PropertyBlockSyntax).PropertyStatement.AttributeLists Case SyntaxKind.PropertyStatement Return DirectCast(node, PropertyStatementSyntax).AttributeLists Case SyntaxKind.OperatorBlock Return DirectCast(node, OperatorBlockSyntax).BlockStatement.AttributeLists Case SyntaxKind.OperatorStatement Return DirectCast(node, OperatorStatementSyntax).AttributeLists Case SyntaxKind.EventBlock Return DirectCast(node, EventBlockSyntax).EventStatement.AttributeLists Case SyntaxKind.EventStatement Return DirectCast(node, EventStatementSyntax).AttributeLists Case SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock, SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock Return DirectCast(node, AccessorBlockSyntax).AccessorStatement.AttributeLists Case SyntaxKind.GetAccessorStatement, SyntaxKind.SetAccessorStatement, SyntaxKind.AddHandlerAccessorStatement, SyntaxKind.RemoveHandlerAccessorStatement, SyntaxKind.RaiseEventAccessorStatement Return DirectCast(node, AccessorStatementSyntax).AttributeLists Case Else Return Nothing End Select End Function ''' <summary> ''' If "node" is the begin statement of a declaration block, return that block, otherwise ''' return node. ''' </summary> <Extension> Public Function GetBlockFromBegin(node As SyntaxNode) As SyntaxNode Dim parent As SyntaxNode = node.Parent Dim begin As SyntaxNode = Nothing If parent IsNot Nothing Then Select Case parent.Kind Case SyntaxKind.NamespaceBlock begin = DirectCast(parent, NamespaceBlockSyntax).NamespaceStatement Case SyntaxKind.ModuleBlock, SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ClassBlock begin = DirectCast(parent, TypeBlockSyntax).BlockStatement Case SyntaxKind.EnumBlock begin = DirectCast(parent, EnumBlockSyntax).EnumStatement Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock, SyntaxKind.ConstructorBlock, SyntaxKind.OperatorBlock, SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock, SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock begin = DirectCast(parent, MethodBlockBaseSyntax).BlockStatement Case SyntaxKind.PropertyBlock begin = DirectCast(parent, PropertyBlockSyntax).PropertyStatement Case SyntaxKind.EventBlock begin = DirectCast(parent, EventBlockSyntax).EventStatement Case SyntaxKind.VariableDeclarator If DirectCast(parent, VariableDeclaratorSyntax).Names.Count = 1 Then begin = node End If End Select End If If begin Is node Then Return parent Else Return node End If End Function <Extension> Public Function GetDeclarationBlockFromBegin(node As DeclarationStatementSyntax) As DeclarationStatementSyntax Dim parent As SyntaxNode = node.Parent Dim begin As SyntaxNode = Nothing If parent IsNot Nothing Then Select Case parent.Kind Case SyntaxKind.NamespaceBlock begin = DirectCast(parent, NamespaceBlockSyntax).NamespaceStatement Case SyntaxKind.ModuleBlock, SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ClassBlock begin = DirectCast(parent, TypeBlockSyntax).BlockStatement Case SyntaxKind.EnumBlock begin = DirectCast(parent, EnumBlockSyntax).EnumStatement Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock, SyntaxKind.ConstructorBlock, SyntaxKind.OperatorBlock, SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock, SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock begin = DirectCast(parent, MethodBlockBaseSyntax).BlockStatement Case SyntaxKind.PropertyBlock begin = DirectCast(parent, PropertyBlockSyntax).PropertyStatement Case SyntaxKind.EventBlock begin = DirectCast(parent, EventBlockSyntax).EventStatement End Select End If If begin Is node Then ' Every one of these parent casts is of a subtype of DeclarationStatementSyntax ' So if the cast worked above, it will work here Return DirectCast(parent, DeclarationStatementSyntax) Else Return node End If End Function Friend Function GetAccessorList(declaration As SyntaxNode) As SyntaxList(Of AccessorBlockSyntax) Select Case declaration.Kind Case SyntaxKind.PropertyBlock Return DirectCast(declaration, PropertyBlockSyntax).Accessors Case SyntaxKind.EventBlock Return DirectCast(declaration, EventBlockSyntax).Accessors Case Else Return Nothing End Select End Function End Module End Namespace