File: Completion\KeywordRecommenders\PreprocessorDirectives\PreprocessorHelpers.vb
Web Access
Project: src\src\roslyn\src\Features\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Features.vbproj (Microsoft.CodeAnalysis.VisualBasic.Features)
' 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.Runtime.CompilerServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax

Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.KeywordRecommenders.PreprocessorDirectives
    Friend Module PreprocessorHelpers
        <Extension()>
        Public Function GetInnermostIfPreprocessorKind(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As SyntaxKind?
            Dim kindStack = New IfDirectiveVisitor(syntaxTree, position, cancellationToken).GetStack()

            If kindStack.Count = 0 Then
                Return Nothing
            Else
                Return kindStack.Peek()
            End If
        End Function

        Private Class IfDirectiveVisitor
            Inherits VisualBasicSyntaxVisitor

            Private ReadOnly _kindStack As New Stack(Of SyntaxKind)
            Private ReadOnly _maxPosition As Integer

            Public Sub New(syntaxTree As SyntaxTree, maxPosition As Integer, cancellationToken As CancellationToken)
                _maxPosition = maxPosition
                Visit(syntaxTree.GetRoot(cancellationToken))
            End Sub

            Public Overrides Sub DefaultVisit(node As SyntaxNode)
                If Not node.ContainsDirectives Then
                    Return
                End If

                For Each leadingTrivia In node.GetLeadingTrivia()
                    If leadingTrivia.HasStructure Then
                        Visit(leadingTrivia.GetStructure())
                    End If
                Next

                For Each child In node.ChildNodesAndTokens()
                    If child.FullSpan.Start > _maxPosition Then
                        Exit For
                    End If

                    If child.IsNode Then
                        Visit(child.AsNode())
                    End If
                Next

                For Each followingTrivia In node.GetTrailingTrivia()
                    If followingTrivia.HasStructure Then
                        Visit(followingTrivia.GetStructure())
                    End If
                Next
            End Sub

            Public Overrides Sub VisitIfDirectiveTrivia(node As IfDirectiveTriviaSyntax)
                If node.Kind = SyntaxKind.IfDirectiveTrivia Then
                    _kindStack.Push(node.Kind)
                ElseIf node.Kind = SyntaxKind.ElseIfDirectiveTrivia Then
                    ' If we're closing our previous context, then pop that one
                    If _kindStack.Count > 0 Then
                        _kindStack.Pop()
                    End If

                    _kindStack.Push(node.Kind)
                End If
            End Sub

            Public Overrides Sub VisitElseDirectiveTrivia(node As ElseDirectiveTriviaSyntax)
                If _kindStack.Count > 0 Then
                    _kindStack.Pop()
                End If

                _kindStack.Push(node.Kind)

            End Sub

            Public Overrides Sub VisitEndIfDirectiveTrivia(node As EndIfDirectiveTriviaSyntax)
                If _kindStack.Count > 0 Then
                    _kindStack.Pop()
                End If
            End Sub

            Public Function GetStack() As Stack(Of SyntaxKind)
                Return _kindStack
            End Function
        End Class
    End Module
End Namespace