File: Syntax\SyntaxTreeDiagnosticEnumerator.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.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.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    Friend Structure SyntaxTreeDiagnosticEnumerator
 
        Private Structure NodeIteration
            Friend ReadOnly node As GreenNode
            Friend diagnosticIndex As Integer
            Friend slotIndex As Integer
            Friend ReadOnly inDocumentationComment As Boolean
 
            Friend Sub New(node As GreenNode, inDocumentationComment As Boolean)
                Me.node = node
                Me.slotIndex = -1
                Me.diagnosticIndex = -1
                Me.inDocumentationComment = inDocumentationComment
            End Sub
        End Structure
 
        Private ReadOnly _tree As SyntaxTree
        Private _stack As NodeIteration()
        Private _count As Integer
        Private _current As Diagnostic
        Private _position As Integer
 
        Friend Sub New(tree As SyntaxTree, node As InternalSyntax.VisualBasicSyntaxNode, position As Integer, inDocumentationComment As Boolean)
            If node IsNot Nothing AndAlso node.ContainsDiagnostics Then
                Me._tree = tree
                Me._stack = New NodeIteration(8 - 1) {}
                Me.Push(node, inDocumentationComment)
            Else
                Me._tree = Nothing
                Me._stack = Nothing
                Me._count = 0
            End If
            Me._current = Nothing
            Me._position = position
        End Sub
 
        Public Function MoveNext() As Boolean
            While _count > 0
 
                Dim diagIndex = Me._stack(_count - 1).diagnosticIndex
                Dim node = Me._stack(_count - 1).node
                Dim diags = node.GetDiagnostics
                Dim inDocumentationComment = Me._stack(_count - 1).inDocumentationComment
 
                If diags IsNot Nothing AndAlso diagIndex < diags.Length - 1 Then
                    diagIndex += 1
                    Dim di = diags(diagIndex)
                    If inDocumentationComment Then
                        di = ErrorFactory.ErrorInfo(ERRID.WRN_XMLDocParseError1, di)
                    End If
 
                    ' Tokens have already processed leading trivia, so only add leading trivia width for non-tokens [bug 4745]
                    Dim position As Integer = Me._position
                    If Not node.IsToken Then
                        position += node.GetLeadingTriviaWidth()
                    End If
 
                    Me._current = New VBDiagnostic(di, Me._tree.GetLocation(New TextSpan(position, node.Width)))
                    Me._stack(_count - 1).diagnosticIndex = diagIndex
                    Return True
                End If
 
                Dim slotIndex = Me._stack(_count - 1).slotIndex
                inDocumentationComment = inDocumentationComment OrElse node.RawKind = SyntaxKind.DocumentationCommentTrivia
 
tryAgain:
                If slotIndex < node.SlotCount - 1 Then
 
                    slotIndex += 1
                    Dim child = node.GetSlot(slotIndex)
 
                    If child Is Nothing Then
                        GoTo tryAgain
                    End If
 
                    If Not child.ContainsDiagnostics Then
                        Me._position += child.FullWidth
                        GoTo tryAgain
                    End If
 
                    Me._stack(_count - 1).slotIndex = slotIndex
 
                    Push(child, inDocumentationComment)
 
                Else
                    If node.SlotCount = 0 Then
                        Me._position += node.Width
                    End If
 
                    Me.Pop()
 
                End If
 
            End While
            Return False
        End Function
 
        Private Sub Push(node As GreenNode, inDocumentationComment As Boolean)
            Dim token = TryCast(node, InternalSyntax.SyntaxToken)
 
            If token IsNot Nothing Then
                PushToken(token, inDocumentationComment)
            Else
                PushNode(node, inDocumentationComment)
            End If
        End Sub
 
        Private Sub PushToken(token As InternalSyntax.SyntaxToken, inDocumentationComment As Boolean)
            Dim trailing = token.GetTrailingTrivia
            If trailing IsNot Nothing Then
                Me.Push(trailing, inDocumentationComment)
            End If
 
            PushNode(token, inDocumentationComment)
 
            Dim leading = token.GetLeadingTrivia
            If leading IsNot Nothing Then
                Me.Push(leading, inDocumentationComment)
            End If
        End Sub
 
        Private Sub PushNode(node As GreenNode, inDocumentationComment As Boolean)
            If Me._count >= Me._stack.Length Then
                Dim tmp As NodeIteration() = New NodeIteration((Me._stack.Length * 2) - 1) {}
                Array.Copy(Me._stack, tmp, Me._stack.Length)
                Me._stack = tmp
            End If
            Me._stack(Me._count) = New NodeIteration(node, inDocumentationComment)
            Me._count += 1
        End Sub
 
        Private Sub Pop()
            Me._count -= 1
        End Sub
 
        Public ReadOnly Property Current As Diagnostic
            Get
                Return Me._current
            End Get
        End Property
 
    End Structure
 
End Namespace