File: CodeModel\VisualBasicCodeModelService.NodeLocator.vb
Web Access
Project: src\src\VisualStudio\VisualBasic\Impl\Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj (Microsoft.VisualStudio.LanguageServices.VisualBasic)
' 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
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities
Imports Microsoft.CodeAnalysis.Formatting
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Utilities
 
Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
    Partial Friend Class VisualBasicCodeModelService
 
        Protected Overrides Function CreateNodeLocator() As AbstractNodeLocator
            Return New NodeLocator()
        End Function
 
        Private Class NodeLocator
            Inherits AbstractNodeLocator
 
            Protected Overrides ReadOnly Property LanguageName As String
                Get
                    Return LanguageNames.VisualBasic
                End Get
            End Property
 
            Protected Overrides ReadOnly Property DefaultPart As EnvDTE.vsCMPart
                Get
                    Return EnvDTE.vsCMPart.vsCMPartWhole
                End Get
            End Property
 
            Protected Overrides Function GetStartPoint(text As SourceText, options As LineFormattingOptions, node As SyntaxNode, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Select Case node.Kind
                    Case SyntaxKind.ClassBlock,
                         SyntaxKind.InterfaceBlock,
                         SyntaxKind.ModuleBlock,
                         SyntaxKind.StructureBlock
                        Return GetTypeBlockStartPoint(text, options, DirectCast(node, TypeBlockSyntax), part)
                    Case SyntaxKind.EnumBlock
                        Return GetEnumBlockStartPoint(text, options, DirectCast(node, EnumBlockSyntax), part)
                    Case SyntaxKind.ClassStatement,
                         SyntaxKind.InterfaceStatement,
                         SyntaxKind.ModuleStatement,
                         SyntaxKind.StructureStatement
                        Return GetTypeBlockStartPoint(text, options, DirectCast(node.Parent, TypeBlockSyntax), part)
                    Case SyntaxKind.EnumStatement
                        Return GetEnumBlockStartPoint(text, options, DirectCast(node.Parent, EnumBlockSyntax), part)
                    Case SyntaxKind.ConstructorBlock,
                         SyntaxKind.FunctionBlock,
                         SyntaxKind.OperatorBlock,
                         SyntaxKind.SubBlock,
                         SyntaxKind.GetAccessorBlock,
                         SyntaxKind.SetAccessorBlock,
                         SyntaxKind.AddHandlerAccessorBlock,
                         SyntaxKind.RemoveHandlerAccessorBlock,
                         SyntaxKind.RaiseEventAccessorBlock
                        Return GetMethodBlockStartPoint(text, options, DirectCast(node, MethodBlockBaseSyntax), part)
                    Case SyntaxKind.SubNewStatement,
                         SyntaxKind.OperatorStatement,
                         SyntaxKind.GetAccessorStatement,
                         SyntaxKind.SetAccessorStatement,
                         SyntaxKind.AddHandlerStatement,
                         SyntaxKind.RemoveHandlerStatement,
                         SyntaxKind.RaiseEventStatement
                        Return GetMethodBlockStartPoint(text, options, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
                    Case SyntaxKind.FunctionStatement,
                         SyntaxKind.SubStatement
                        If TypeOf node.Parent Is MethodBlockBaseSyntax Then
                            Return GetMethodBlockStartPoint(text, options, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
                        Else
                            Return GetMethodStatementStartPoint(text, DirectCast(node, MethodStatementSyntax), part)
                        End If
 
                    Case SyntaxKind.DeclareFunctionStatement,
                         SyntaxKind.DeclareSubStatement
                        Return GetDeclareStatementStartPoint(text, DirectCast(node, DeclareStatementSyntax), part)
                    Case SyntaxKind.PropertyBlock
                        Return GetPropertyBlockStartPoint(text, DirectCast(node, PropertyBlockSyntax), part)
                    Case SyntaxKind.PropertyStatement
                        Return GetPropertyStatementStartPoint(text, DirectCast(node, PropertyStatementSyntax), part)
 
                    Case SyntaxKind.EventBlock
                        Return GetEventBlockStartPoint(text, options, DirectCast(node, EventBlockSyntax), part)
                    Case SyntaxKind.EventStatement
                        Return GetEventStatementStartPoint(text, DirectCast(node, EventStatementSyntax), part)
 
                    Case SyntaxKind.DelegateFunctionStatement,
                         SyntaxKind.DelegateSubStatement
                        Return GetDelegateStatementStartPoint(text, DirectCast(node, DelegateStatementSyntax), part)
 
                    Case SyntaxKind.NamespaceBlock
                        Return GetNamespaceBlockStartPoint(text, options, DirectCast(node, NamespaceBlockSyntax), part)
                    Case SyntaxKind.NamespaceStatement
                        Return GetNamespaceBlockStartPoint(text, options, DirectCast(node.Parent, NamespaceBlockSyntax), part)
                    Case SyntaxKind.ModifiedIdentifier
                        Return GetVariableStartPoint(text, DirectCast(node, ModifiedIdentifierSyntax), part)
                    Case SyntaxKind.EnumMemberDeclaration
                        Return GetVariableStartPoint(text, DirectCast(node, EnumMemberDeclarationSyntax), part)
                    Case SyntaxKind.Parameter
                        Return GetParameterStartPoint(text, DirectCast(node, ParameterSyntax), part)
 
                    Case SyntaxKind.Attribute
                        Return GetAttributeStartPoint(text, DirectCast(node, AttributeSyntax), part)
                    Case SyntaxKind.SimpleArgument,
                         SyntaxKind.OmittedArgument
                        Return GetAttributeArgumentStartPoint(text, DirectCast(node, ArgumentSyntax), part)
 
                    Case SyntaxKind.SimpleImportsClause
                        Return GetImportsStatementStartPoint(text, DirectCast(node.Parent, ImportsStatementSyntax), part)
                    Case SyntaxKind.OptionStatement
                        Return GetOptionStatementStartPoint(text, DirectCast(node, OptionStatementSyntax), part)
                    Case SyntaxKind.InheritsStatement
                        Return GetInheritsStatementStartPoint(text, DirectCast(node, InheritsStatementSyntax), part)
                    Case SyntaxKind.ImplementsStatement
                        Return GetImplementsStatementStartPoint(text, DirectCast(node, ImplementsStatementSyntax), part)
                    Case Else
                        Debug.Fail(String.Format("Unsupported node kind: {0}", CType(node.Kind, SyntaxKind)))
                        Throw New NotSupportedException()
                End Select
            End Function
 
            Protected Overrides Function GetEndPoint(text As SourceText, options As LineFormattingOptions, node As SyntaxNode, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Select Case node.Kind
                    Case SyntaxKind.ClassBlock,
                         SyntaxKind.InterfaceBlock,
                         SyntaxKind.ModuleBlock,
                         SyntaxKind.StructureBlock
                        Return GetTypeBlockEndPoint(text, DirectCast(node, TypeBlockSyntax), part)
                    Case SyntaxKind.EnumBlock
                        Return GetEnumBlockEndPoint(text, DirectCast(node, EnumBlockSyntax), part)
                    Case SyntaxKind.ClassStatement,
                         SyntaxKind.InterfaceStatement,
                         SyntaxKind.ModuleBlock,
                         SyntaxKind.StructureBlock
                        Return GetTypeBlockEndPoint(text, DirectCast(node.Parent, TypeBlockSyntax), part)
                    Case SyntaxKind.EnumStatement
                        Return GetEnumBlockEndPoint(text, DirectCast(node.Parent, EnumBlockSyntax), part)
                    Case SyntaxKind.ConstructorBlock,
                         SyntaxKind.FunctionBlock,
                         SyntaxKind.OperatorBlock,
                         SyntaxKind.SubBlock,
                         SyntaxKind.GetAccessorBlock,
                         SyntaxKind.SetAccessorBlock,
                         SyntaxKind.AddHandlerAccessorBlock,
                         SyntaxKind.RemoveHandlerAccessorBlock,
                         SyntaxKind.RaiseEventAccessorBlock
                        Return GetMethodBlockEndPoint(text, DirectCast(node, MethodBlockBaseSyntax), part)
                    Case SyntaxKind.SubNewStatement,
                         SyntaxKind.OperatorStatement,
                         SyntaxKind.GetAccessorStatement,
                         SyntaxKind.SetAccessorStatement,
                         SyntaxKind.AddHandlerStatement,
                         SyntaxKind.RemoveHandlerStatement,
                         SyntaxKind.RaiseEventStatement
                        Return GetMethodBlockEndPoint(text, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
                    Case SyntaxKind.FunctionStatement,
                         SyntaxKind.SubStatement
                        If TypeOf node.Parent Is MethodBlockBaseSyntax Then
                            Return GetMethodBlockEndPoint(text, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
                        Else
                            Return GetMethodStatementEndPoint(text, DirectCast(node, MethodStatementSyntax), part)
                        End If
 
                    Case SyntaxKind.DeclareFunctionStatement,
                         SyntaxKind.DeclareSubStatement
                        Return GetDeclareStatementEndPoint(text, DirectCast(node, DeclareStatementSyntax), part)
                    Case SyntaxKind.PropertyBlock
                        Return GetPropertyBlockEndPoint(text, DirectCast(node, PropertyBlockSyntax), part)
                    Case SyntaxKind.PropertyStatement
                        Return GetPropertyStatementEndPoint(text, DirectCast(node, PropertyStatementSyntax), part)
 
                    Case SyntaxKind.EventBlock
                        Return GetEventBlockEndPoint(text, DirectCast(node, EventBlockSyntax), part)
                    Case SyntaxKind.EventStatement
                        Return GetEventStatementEndPoint(text, DirectCast(node, EventStatementSyntax), part)
 
                    Case SyntaxKind.DelegateFunctionStatement,
                         SyntaxKind.DelegateSubStatement
                        Return GetDelegateStatementEndPoint(text, DirectCast(node, DelegateStatementSyntax), part)
 
                    Case SyntaxKind.NamespaceBlock
                        Return GetNamespaceBlockEndPoint(text, DirectCast(node, NamespaceBlockSyntax), part)
                    Case SyntaxKind.NamespaceStatement
                        Return GetNamespaceBlockEndPoint(text, DirectCast(node.Parent, NamespaceBlockSyntax), part)
                    Case SyntaxKind.ModifiedIdentifier
                        Return GetVariableEndPoint(text, DirectCast(node, ModifiedIdentifierSyntax), part)
                    Case SyntaxKind.EnumMemberDeclaration
                        Return GetVariableEndPoint(text, DirectCast(node, EnumMemberDeclarationSyntax), part)
                    Case SyntaxKind.Parameter
                        Return GetParameterEndPoint(text, DirectCast(node, ParameterSyntax), part)
 
                    Case SyntaxKind.Attribute
                        Return GetAttributeEndPoint(text, DirectCast(node, AttributeSyntax), part)
                    Case SyntaxKind.SimpleArgument,
                         SyntaxKind.OmittedArgument
                        Return GetAttributeArgumentEndPoint(text, DirectCast(node, ArgumentSyntax), part)
 
                    Case SyntaxKind.SimpleImportsClause
                        Return GetImportsStatementEndPoint(text, DirectCast(node.Parent, ImportsStatementSyntax), part)
                    Case SyntaxKind.OptionStatement
                        Return GetOptionStatementEndPoint(text, DirectCast(node, OptionStatementSyntax), part)
                    Case SyntaxKind.InheritsStatement
                        Return GetInheritsStatementEndPoint(text, DirectCast(node, InheritsStatementSyntax), part)
                    Case SyntaxKind.ImplementsStatement
                        Return GetImplementsStatementEndPoint(text, DirectCast(node, ImplementsStatementSyntax), part)
                    Case Else
                        Debug.Fail(String.Format("Unsupported node kind: {0}", CType(node.Kind, SyntaxKind)))
                        Throw New NotImplementedException()
                End Select
            End Function
 
            Private Shared Function GetAttributesStartPoint(text As SourceText, attributes As SyntaxList(Of AttributeListSyntax), part As EnvDTE.vsCMPart) As VirtualTreePoint?
                ' VB has a Code Model bug that causes vsCMPartAttributes and vsCMPartAttributesWithDelimiters to return the same value.
                ' You can see the issue clearly in vb\Language\VsPackage\CodeModelHelpers.cpp, CodeModelLocations::GetAttributeSpecifierListLocation.
                ' Essentially, the old code tries to do the right thing for vsCMPartAttributes, but then deliberately falls through to the
                ' vsCMPartAttributesWithDelimiter case, where it overwrites the calculation it just made. Sigh...
 
                If attributes.Count = 0 Then
                    Return Nothing
                End If
 
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        startPosition = attributes.First().LessThanToken.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        Return Nothing
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(attributes.First().SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetAttributesEndPoint(text As SourceText, attributes As SyntaxList(Of AttributeListSyntax), part As EnvDTE.vsCMPart) As VirtualTreePoint?
                ' VB has a Code Model bug that causes vsCMPartAttributes and vsCMPartAttributesWithDelimiters to return the same value.
                ' See GetAttributesStartPoint for the details
 
                If attributes.Count = 0 Then
                    Return Nothing
                End If
 
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        startPosition = attributes.Last().GreaterThanToken.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        Return Nothing
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(attributes.Last().SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetHeaderStartPosition(typeBlock As TypeBlockSyntax) As Integer
                If typeBlock.BlockStatement.Modifiers.Count > 0 Then
                    Return typeBlock.BlockStatement.Modifiers.First().SpanStart
                Else
                    Return typeBlock.BlockStatement.DeclarationKeyword.SpanStart
                End If
            End Function
 
            Private Shared Function GetHeaderStartPosition(enumBlock As EnumBlockSyntax) As Integer
                If enumBlock.EnumStatement.Modifiers.Count > 0 Then
                    Return enumBlock.EnumStatement.Modifiers.First().SpanStart
                Else
                    Return enumBlock.EnumStatement.EnumKeyword.SpanStart
                End If
            End Function
 
            Private Shared Function GetTypeBlockStartPoint(text As SourceText, options As LineFormattingOptions, typeBlock As TypeBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = typeBlock.BlockStatement.Identifier.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, typeBlock.BlockStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = typeBlock.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole
                        startPosition = GetHeaderStartPosition(typeBlock)
                    Case EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        Dim statement As StatementSyntax = typeBlock.BlockStatement
                        While statement IsNot Nothing
                            Dim [next] = statement.GetNextNonEmptyStatement()
                            If [next] IsNot Nothing AndAlso
                              ([next].Kind = SyntaxKind.InheritsStatement OrElse
                               [next].Kind = SyntaxKind.ImplementsStatement) Then
                                statement = [next]
                                Continue While
                            Else
                                Exit While
                            End If
                        End While
 
                        Debug.Assert(statement IsNot Nothing)
 
                        Dim statementLine = text.Lines.GetLineFromPosition(statement.SpanStart)
 
                        ' statement points to either the last Inherits/Implements or to the type declaration itself.
                        Dim nextStatement = statement.GetNextNonEmptyStatement()
                        Dim nextStatementLine As Nullable(Of TextLine) = If(nextStatement IsNot Nothing, text.Lines.GetLineFromPosition(nextStatement.SpanStart), Nothing)
 
                        ' If the next statement is on the same line as the current one, set body start
                        ' position to the end of the current statement
                        If nextStatementLine IsNot Nothing AndAlso nextStatementLine.Value.LineNumber = statementLine.LineNumber Then
                            startPosition = statement.Span.End
                        Else
                            ' Otherwise, use the beginning of the next line.
                            startPosition = text.Lines(statementLine.LineNumber + 1).Start
                        End If
 
                        If part = EnvDTE.vsCMPart.vsCMPartNavigate Then
                            Return NavigationPointHelpers.GetNavigationPoint(text, options.TabSize, typeBlock.BlockStatement, statementLine.LineNumber + 1)
                        End If
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(typeBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetTypeBlockEndPoint(text As SourceText, typeBlock As TypeBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = typeBlock.BlockStatement.Identifier.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesEndPoint(text, typeBlock.BlockStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes
                        startPosition = typeBlock.BlockStatement.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = typeBlock.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        startPosition = typeBlock.EndBlockStatement.SpanStart
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(typeBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetEnumBlockStartPoint(text As SourceText, options As LineFormattingOptions, enumBlock As EnumBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = enumBlock.EnumStatement.Identifier.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, enumBlock.EnumStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = enumBlock.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole
                        startPosition = GetHeaderStartPosition(enumBlock)
                    Case EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        Dim statement As StatementSyntax = enumBlock.EnumStatement
                        Dim statementLine = text.Lines.GetLineFromPosition(statement.SpanStart)
 
                        Dim nextStatement = statement.GetNextNonEmptyStatement()
                        Dim nextStatementLine As Nullable(Of TextLine) = If(nextStatement IsNot Nothing, text.Lines.GetLineFromPosition(nextStatement.SpanStart), Nothing)
 
                        ' If the next statement is on the same line as the current one, set body start
                        ' position to the end of the current statement
                        If nextStatementLine IsNot Nothing AndAlso nextStatementLine.Value.LineNumber = statementLine.LineNumber Then
                            startPosition = statement.Span.End
                        Else
                            ' Otherwise, use the beginning of the next line.
                            startPosition = text.Lines(statementLine.LineNumber + 1).Start
                        End If
 
                        If part = EnvDTE.vsCMPart.vsCMPartNavigate Then
                            Return NavigationPointHelpers.GetNavigationPoint(text, options.TabSize, enumBlock.EnumStatement, statementLine.LineNumber + 1)
                        End If
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(enumBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetEnumBlockEndPoint(text As SourceText, enumBlock As EnumBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = enumBlock.EnumStatement.Identifier.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesEndPoint(text, enumBlock.EnumStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes
                        startPosition = enumBlock.EnumStatement.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = enumBlock.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        startPosition = enumBlock.EndEnumStatement.SpanStart
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(enumBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetMethodBlockStartPoint(text As SourceText, options As LineFormattingOptions, methodBlock As MethodBlockBaseSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        Select Case methodBlock.BlockStatement.Kind
                            Case SyntaxKind.SubNewStatement
                                startPosition = DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax).NewKeyword.SpanStart
                            Case SyntaxKind.FunctionStatement,
                                 SyntaxKind.SubStatement
                                startPosition = DirectCast(methodBlock.BlockStatement, MethodStatementSyntax).Identifier.SpanStart
                            Case SyntaxKind.OperatorStatement
                                startPosition = DirectCast(methodBlock.BlockStatement, OperatorStatementSyntax).OperatorToken.SpanStart
                            Case SyntaxKind.GetAccessorStatement,
                                 SyntaxKind.SetAccessorStatement
                                ' For properties accessors, use the name of property block
                                Dim propertyBlock = methodBlock.FirstAncestorOrSelf(Of PropertyBlockSyntax)()
                                If propertyBlock Is Nothing Then
                                    Throw Exceptions.ThrowEFail()
                                End If
 
                                Return GetPropertyBlockStartPoint(text, propertyBlock, part)
                            Case SyntaxKind.AddHandlerAccessorStatement,
                                 SyntaxKind.RemoveHandlerAccessorStatement,
                                 SyntaxKind.RaiseEventAccessorStatement
                                ' For event accessors, use the name of event block
                                Dim eventBlock = methodBlock.FirstAncestorOrSelf(Of EventBlockSyntax)()
                                If eventBlock Is Nothing Then
                                    Throw Exceptions.ThrowEFail()
                                End If
 
                                Return GetEventBlockStartPoint(text, options, eventBlock, part)
                            Case Else
                                Throw Exceptions.ThrowEFail()
                        End Select
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, methodBlock.BlockStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = methodBlock.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole
                        startPosition = NavigationPointHelpers.GetHeaderStartPosition(methodBlock)
                    Case EnvDTE.vsCMPart.vsCMPartNavigate
                        Return NavigationPointHelpers.GetNavigationPoint(text, options.TabSize, methodBlock)
                    Case EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        Dim startLine = text.Lines.GetLineFromPosition(NavigationPointHelpers.GetHeaderStartPosition(methodBlock))
                        startPosition = text.Lines(startLine.LineNumber + 1).Start
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(methodBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetDeclareStatementStartPoint(text As SourceText, declareStatement As DeclareStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = declareStatement.Identifier.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesStartPoint(text, declareStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        If declareStatement.AttributeLists.Count > 0 Then
                            startPosition = declareStatement.AttributeLists.Last().GetLastToken().GetNextToken().SpanStart
                        Else
                            startPosition = declareStatement.SpanStart
                        End If
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = declareStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(declareStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetDeclareStatementEndPoint(text As SourceText, declareStatement As DeclareStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = declareStatement.Identifier.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesEndPoint(text, declareStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = declareStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(declareStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetMethodStatementStartPoint(text As SourceText, methodStatement As MethodStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = methodStatement.Identifier.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesStartPoint(text, methodStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        If methodStatement.AttributeLists.Count > 0 Then
                            startPosition = methodStatement.AttributeLists.Last().GetLastToken().GetNextToken().SpanStart
                        Else
                            startPosition = methodStatement.SpanStart
                        End If
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = methodStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(methodStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetMethodBlockEndPoint(text As SourceText, methodBlock As MethodBlockBaseSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        Select Case methodBlock.BlockStatement.Kind
                            Case SyntaxKind.SubNewStatement
                                startPosition = DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax).NewKeyword.Span.End
                            Case SyntaxKind.FunctionStatement,
                                 SyntaxKind.SubStatement
                                startPosition = DirectCast(methodBlock.BlockStatement, MethodStatementSyntax).Identifier.Span.End
                            Case SyntaxKind.OperatorStatement
                                startPosition = DirectCast(methodBlock.BlockStatement, OperatorStatementSyntax).OperatorToken.Span.End
                            Case SyntaxKind.GetAccessorStatement,
                                 SyntaxKind.SetAccessorStatement
                                ' For properties accessors, use the name of property block
                                Dim propertyBlock = methodBlock.FirstAncestorOrSelf(Of PropertyBlockSyntax)()
                                If propertyBlock Is Nothing Then
                                    Throw Exceptions.ThrowEFail()
                                End If
 
                                Return GetPropertyBlockEndPoint(text, propertyBlock, part)
                            Case SyntaxKind.AddHandlerAccessorStatement,
                                 SyntaxKind.RemoveHandlerAccessorStatement,
                                 SyntaxKind.RaiseEventAccessorStatement
                                ' For event accessors, use the name of event block
                                Dim eventBlock = methodBlock.FirstAncestorOrSelf(Of EventBlockSyntax)()
                                If eventBlock Is Nothing Then
                                    Throw Exceptions.ThrowEFail()
                                End If
 
                                Return GetEventBlockEndPoint(text, eventBlock, part)
                            Case Else
                                Throw Exceptions.ThrowEFail()
                        End Select
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesEndPoint(text, methodBlock.BlockStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes
                        startPosition = methodBlock.BlockStatement.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = methodBlock.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        startPosition = methodBlock.EndBlockStatement.SpanStart
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(methodBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetMethodStatementEndPoint(text As SourceText, methodStatement As MethodStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = methodStatement.Identifier.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesEndPoint(text, methodStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = methodStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(methodStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetPropertyBlockStartPoint(text As SourceText, propertyBlock As PropertyBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Return GetPropertyStatementStartPoint(text, propertyBlock.PropertyStatement, part)
            End Function
 
            Private Shared Function GetPropertyStatementStartPoint(text As SourceText, propertyStatement As PropertyStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = propertyStatement.Identifier.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, propertyStatement.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole
                        If propertyStatement.AttributeLists.Count > 0 Then
                            startPosition = propertyStatement.AttributeLists.Last().GetLastToken().GetNextToken().SpanStart
                        Else
                            startPosition = propertyStatement.SpanStart
                        End If
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = propertyStatement.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        Dim beginLine = text.Lines.IndexOf(propertyStatement.Span.End)
 
                        Dim lineNumber = beginLine + 1
                        startPosition = text.Lines(lineNumber).Start
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(propertyStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetPropertyBlockEndPoint(text As SourceText, propertyBlock As PropertyBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Return GetPropertyStatementEndPoint(text, propertyBlock.PropertyStatement, part)
            End Function
 
            Private Shared Function GetPropertyStatementEndPoint(text As SourceText, propertyStatement As PropertyStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
 
                        startPosition = propertyStatement.Identifier.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesEndPoint(text, propertyStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes
 
                        startPosition = propertyStatement.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = If(propertyStatement.IsParentKind(SyntaxKind.PropertyBlock),
                                           DirectCast(propertyStatement.Parent, PropertyBlockSyntax).EndPropertyStatement.Span.End,
                                           propertyStatement.Span.End)
 
                    Case EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter,
                         EnvDTE.vsCMPart.vsCMPartNavigate
 
                        ' Oddity of VB code model: this only happens if it isn't an auto-property. Otherwise, the start of the file is returned.
                        startPosition = If(propertyStatement.IsParentKind(SyntaxKind.PropertyBlock),
                                           DirectCast(propertyStatement.Parent, PropertyBlockSyntax).EndPropertyStatement.SpanStart,
                                           0)
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(propertyStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetEventBlockStartPoint(text As SourceText, options As LineFormattingOptions, eventBlock As EventBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
 
                        startPosition = eventBlock.EventStatement.Identifier.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesStartPoint(text, eventBlock.EventStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = eventBlock.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole
 
                        startPosition = NavigationPointHelpers.GetHeaderStartPosition(eventBlock)
 
                    Case EnvDTE.vsCMPart.vsCMPartNavigate
 
                        Return NavigationPointHelpers.GetNavigationPoint(text, options.TabSize, eventBlock)
 
                    Case EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        Dim startLine = text.Lines.GetLineFromPosition(NavigationPointHelpers.GetHeaderStartPosition(eventBlock))
                        startPosition = text.Lines(startLine.LineNumber + 1).Start
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(eventBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetEventStatementStartPoint(text As SourceText, eventStatement As EventStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
 
                        startPosition = eventStatement.Identifier.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesStartPoint(text, eventStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        If eventStatement.AttributeLists.Count > 0 Then
                            startPosition = eventStatement.AttributeLists.Last().GetLastToken().GetNextToken().SpanStart
                        Else
                            startPosition = eventStatement.SpanStart
                        End If
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = eventStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(eventStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetEventBlockEndPoint(text As SourceText, eventBlock As EventBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Return GetEventStatementEndPoint(text, eventBlock.EventStatement, part)
            End Function
 
            Private Shared Function GetEventStatementEndPoint(text As SourceText, eventStatement As EventStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
 
                    Case EnvDTE.vsCMPart.vsCMPartName
 
                        startPosition = eventStatement.Identifier.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesEndPoint(text, eventStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes
 
                        startPosition = eventStatement.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = If(eventStatement.IsParentKind(SyntaxKind.EventBlock),
                                           DirectCast(eventStatement.Parent, EventBlockSyntax).EndEventStatement.Span.End,
                                           eventStatement.Span.End)
 
                    Case EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter,
                         EnvDTE.vsCMPart.vsCMPartNavigate
 
                        startPosition = If(eventStatement.IsParentKind(SyntaxKind.EventBlock),
                                           DirectCast(eventStatement.Parent, EventBlockSyntax).EndEventStatement.SpanStart,
                                           eventStatement.Span.End)
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(eventStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetDelegateStatementStartPoint(text As SourceText, delegateStatement As DelegateStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = delegateStatement.Identifier.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesStartPoint(text, delegateStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        If delegateStatement.AttributeLists.Count > 0 Then
                            startPosition = delegateStatement.AttributeLists.Last().GetLastToken().GetNextToken().SpanStart
                        Else
                            startPosition = delegateStatement.SpanStart
                        End If
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
 
                        startPosition = delegateStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(delegateStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetDelegateStatementEndPoint(text As SourceText, delegateStatement As DelegateStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = delegateStatement.Identifier.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
 
                        Return GetAttributesEndPoint(text, delegateStatement.AttributeLists, part)
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = delegateStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(delegateStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetTrailingColonTrivia(statement As StatementSyntax) As SyntaxTrivia?
                If Not statement.HasTrailingTrivia Then
                    Return Nothing
                End If
 
                Return statement _
                    .GetTrailingTrivia() _
                    .FirstOrNull(Function(t) t.Kind = SyntaxKind.ColonTrivia)
            End Function
 
            Private Shared Function GetNamespaceBlockStartPoint(text As SourceText, options As LineFormattingOptions, namespaceBlock As NamespaceBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = namespaceBlock.NamespaceStatement.Name.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole
                        startPosition = namespaceBlock.NamespaceStatement.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartNavigate
                        Dim beginStatement = namespaceBlock.NamespaceStatement
 
                        Dim beginLine = text.Lines.IndexOf(beginStatement.SpanStart)
                        Dim lineNumber = beginLine + 1
 
                        ' If the begin statement has trailing colon trivia, we assume the body starts at the colon.
                        Dim colonTrivia = GetTrailingColonTrivia(beginStatement)
                        If colonTrivia IsNot Nothing Then
                            lineNumber = text.Lines.IndexOf(colonTrivia.Value.SpanStart)
                        End If
 
                        Return NavigationPointHelpers.GetNavigationPoint(text, options.TabSize, namespaceBlock.NamespaceStatement, lineNumber)
 
                    Case EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        Dim beginStatement = namespaceBlock.NamespaceStatement
                        Dim endStatement = namespaceBlock.EndNamespaceStatement
 
                        ' Handle case where begin statement has trailing colon trivia, e.g. Namespace N : End Namespace
                        Dim colonTrivia = GetTrailingColonTrivia(beginStatement)
                        If colonTrivia IsNot Nothing Then
                            startPosition = colonTrivia.Value.SpanStart
                            Exit Select
                        End If
 
                        Dim beginLine = text.Lines.IndexOf(beginStatement.SpanStart)
 
                        Dim lineNumber = beginLine + 1
                        startPosition = text.Lines(lineNumber).Start
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(namespaceBlock.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetNamespaceBlockEndPoint(text As SourceText, namespaceBlock As NamespaceBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = namespaceBlock.NamespaceStatement.Name.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader
                        endPosition = namespaceBlock.NamespaceStatement.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole
                        endPosition = namespaceBlock.EndNamespaceStatement.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter,
                         EnvDTE.vsCMPart.vsCMPartNavigate
 
                        endPosition = namespaceBlock.EndNamespaceStatement.SpanStart
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(namespaceBlock.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetVariableStartPoint(text As SourceText, variable As ModifiedIdentifierSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim fieldDeclaration = variable.FirstAncestorOrSelf(Of FieldDeclarationSyntax)()
                Debug.Assert(fieldDeclaration IsNot Nothing)
 
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = variable.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, fieldDeclaration.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = fieldDeclaration.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        If fieldDeclaration.Modifiers.Count > 0 Then
                            startPosition = fieldDeclaration.Modifiers.First().SpanStart
                        Else
                            startPosition = fieldDeclaration.Declarators.First().SpanStart
                        End If
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(variable.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetVariableStartPoint(text As SourceText, enumMember As EnumMemberDeclarationSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = enumMember.Identifier.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, enumMember.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = enumMember.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        startPosition = enumMember.Identifier.SpanStart
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(enumMember.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetVariableEndPoint(text As SourceText, variable As ModifiedIdentifierSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim fieldDeclaration = variable.FirstAncestorOrSelf(Of FieldDeclarationSyntax)()
                Debug.Assert(fieldDeclaration IsNot Nothing)
 
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = variable.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesEndPoint(text, fieldDeclaration.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        endPosition = fieldDeclaration.Span.End
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(variable.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetVariableEndPoint(text As SourceText, enumMember As EnumMemberDeclarationSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = enumMember.Identifier.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesEndPoint(text, enumMember.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        endPosition = enumMember.Span.End
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(enumMember.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetParameterStartPoint(text As SourceText, parameter As ParameterSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = parameter.Identifier.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesStartPoint(text, parameter.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes
                        startPosition = parameter.SpanStart
                    Case EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        If parameter.Modifiers.Any() Then
                            startPosition = parameter.Modifiers.First().SpanStart
                        Else
                            startPosition = parameter.Identifier.SpanStart
                        End If
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(parameter.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetParameterEndPoint(text As SourceText, parameter As ParameterSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = parameter.Identifier.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return GetAttributesEndPoint(text, parameter.AttributeLists, part)
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
                        endPosition = parameter.Span.End
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(parameter.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetImportsStatementStartPoint(text As SourceText, importsStatement As ImportsStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        startPosition = importsStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(importsStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetImportsStatementEndPoint(text As SourceText, importsStatement As ImportsStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = importsStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(importsStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetOptionStatementStartPoint(text As SourceText, optionStatement As OptionStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        startPosition = optionStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(optionStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetOptionStatementEndPoint(text As SourceText, optionStatement As OptionStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = optionStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(optionStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetInheritsStatementStartPoint(text As SourceText, inheritsStatement As InheritsStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        startPosition = inheritsStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(inheritsStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetInheritsStatementEndPoint(text As SourceText, inheritsStatement As InheritsStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = inheritsStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(inheritsStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetImplementsStatementStartPoint(text As SourceText, implementsStatement As ImplementsStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        startPosition = implementsStatement.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(implementsStatement.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetImplementsStatementEndPoint(text As SourceText, implementsStatement As ImplementsStatementSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = implementsStatement.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(implementsStatement.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetAttributeStartPoint(text As SourceText, attribute As AttributeSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartName
                        startPosition = attribute.Name.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        startPosition = attribute.SpanStart
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(attribute.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetAttributeEndPoint(text As SourceText, attribute As AttributeSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartName
                        endPosition = attribute.Name.Span.End
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = attribute.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(attribute.SyntaxTree, text, endPosition)
            End Function
 
            Private Shared Function GetAttributeArgumentStartPoint(text As SourceText, argument As ArgumentSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim startPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartName
                        If Not argument.IsNamed Then
                            Return Nothing
                        End If
 
                        startPosition = DirectCast(argument, SimpleArgumentSyntax).NameColonEquals.Name.SpanStart
 
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        startPosition = If(argument.Kind = SyntaxKind.OmittedArgument,
                                           argument.SpanStart - 1,
                                           argument.SpanStart)
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(argument.SyntaxTree, text, startPosition)
            End Function
 
            Private Shared Function GetAttributeArgumentEndPoint(text As SourceText, argument As ArgumentSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
                Dim endPosition As Integer
 
                Select Case part
                    Case EnvDTE.vsCMPart.vsCMPartAttributes,
                         EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter
                        Return Nothing
 
                    Case EnvDTE.vsCMPart.vsCMPartName
                        If Not argument.IsNamed Then
 
                            Return Nothing
 
                        End If
 
                        endPosition = DirectCast(argument, SimpleArgumentSyntax).NameColonEquals.Name.Span.End
                    Case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartHeader,
                         EnvDTE.vsCMPart.vsCMPartWholeWithAttributes,
                         EnvDTE.vsCMPart.vsCMPartWhole,
                         EnvDTE.vsCMPart.vsCMPartNavigate,
                         EnvDTE.vsCMPart.vsCMPartName,
                         EnvDTE.vsCMPart.vsCMPartBody,
                         EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
 
                        endPosition = argument.Span.End
 
                    Case Else
                        Throw Exceptions.ThrowEFail()
                End Select
 
                Return New VirtualTreePoint(argument.SyntaxTree, text, endPosition)
            End Function
 
        End Class
    End Class
End Namespace