File: Debugging\ProximityExpressionsGetter.Worker.vb
Web Access
Project: src\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.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging
    Partial Friend Class VisualBasicProximityExpressionsService
        Public Class Worker
 
            Private ReadOnly _syntaxTree As SyntaxTree
            Private ReadOnly _position As Integer
 
            Private _parentStatement As StatementSyntax
            Private ReadOnly _additionalTerms As New List(Of String)()
            Private ReadOnly _expressions As New List(Of ExpressionSyntax)()
 
            Public Sub New(syntaxTree As SyntaxTree, position As Integer)
                _syntaxTree = syntaxTree
                _position = position
            End Sub
 
            Friend Function [Do](cancellationToken As CancellationToken) As IList(Of String)
                Dim token = _syntaxTree.GetRoot(cancellationToken).FindToken(_position)
 
                _parentStatement = token.GetAncestor(Of StatementSyntax)()
                If _parentStatement Is Nothing Then
                    Return Nothing
                End If
 
                AddRelevantExpressions(_parentStatement, _expressions, includeDeclarations:=False)
                AddPrecedingRelevantExpressions()
                AddFollowingRelevantExpressions(cancellationToken)
                AddCurrentDeclaration()
                AddMethodParameters()
                AddCatchParameters()
                AddMeExpression()
 
                Dim terms = New List(Of String)()
                _expressions.Do(Sub(e) AddExpressionTerms(e, terms))
                terms.AddRange(_additionalTerms)
 
                Dim proximityExpressions = terms.Distinct().ToList()
 
                Return If(proximityExpressions.Count = 0, Nothing, proximityExpressions)
            End Function
 
            Private Sub AddPrecedingRelevantExpressions()
                Dim previousStatement = _parentStatement.GetPreviousStatement()
 
                If previousStatement IsNot Nothing Then
                    ' Note: FieldDeclaration statements are interesting as the current statement, 
                    ' but not as the preceding statement (as in dev12).
                    Select Case (previousStatement.Kind)
                        Case SyntaxKind.LocalDeclarationStatement,
                             SyntaxKind.CallStatement,
                             SyntaxKind.ExpressionStatement,
                             SyntaxKind.AddHandlerStatement,
                             SyntaxKind.RemoveHandlerStatement,
                             SyntaxKind.RaiseEventStatement,
                             SyntaxKind.YieldStatement,
                             SyntaxKind.ReturnStatement,
                             SyntaxKind.ReDimStatement,
                             SyntaxKind.EraseStatement,
                             SyntaxKind.MidAssignmentStatement,
                             SyntaxKind.SimpleAssignmentStatement,
                             SyntaxKind.AddAssignmentStatement,
                             SyntaxKind.SubtractAssignmentStatement,
                             SyntaxKind.MultiplyAssignmentStatement,
                             SyntaxKind.DivideAssignmentStatement,
                             SyntaxKind.IntegerDivideAssignmentStatement,
                             SyntaxKind.ExponentiateAssignmentStatement,
                             SyntaxKind.LeftShiftAssignmentStatement,
                             SyntaxKind.RightShiftAssignmentStatement,
                             SyntaxKind.ConcatenateAssignmentStatement
 
                            AddRelevantExpressions(previousStatement, _expressions, includeDeclarations:=True)
                    End Select
                End If
            End Sub
 
            Private Sub AddFollowingRelevantExpressions(cancellationToken As CancellationToken)
                Dim line = _syntaxTree.GetText(cancellationToken).Lines.IndexOf(_position)
                Dim nextStatement = _parentStatement.GetNextStatement()
 
                While nextStatement IsNot Nothing AndAlso _syntaxTree.GetText(cancellationToken).Lines.IndexOf(nextStatement.SpanStart) = line
                    AddRelevantExpressions(nextStatement, _expressions, includeDeclarations:=False)
                    nextStatement = nextStatement.GetNextStatement()
                End While
            End Sub
 
            Private Sub AddCurrentDeclaration()
                If TypeOf _parentStatement Is LocalDeclarationStatementSyntax OrElse
                   TypeOf _parentStatement Is FieldDeclarationSyntax Then
                    AddRelevantExpressions(_parentStatement, _expressions, includeDeclarations:=True)
                End If
            End Sub
 
            Private Sub AddMethodParameters()
                If TypeOf _parentStatement.Parent Is MethodBlockBaseSyntax Then
                    Dim methodBlock = DirectCast(_parentStatement.Parent, MethodBlockBaseSyntax)
 
                    If methodBlock.BlockStatement Is _parentStatement OrElse
                        methodBlock.Statements.FirstOrDefault() Is _parentStatement OrElse
                        methodBlock.EndBlockStatement Is _parentStatement Then
 
                        If methodBlock.BlockStatement.ParameterList IsNot Nothing Then
                            For Each p In methodBlock.BlockStatement.ParameterList.Parameters
                                _additionalTerms.Add(p.Identifier.Identifier.ValueText)
                            Next
                        End If
                    End If
                End If
            End Sub
 
            Private Sub AddCatchParameters()
                If TypeOf _parentStatement.Parent Is CatchBlockSyntax Then
                    Dim catchBlock = DirectCast(_parentStatement.Parent, CatchBlockSyntax)
                    If catchBlock.Statements.FirstOrDefault() Is _parentStatement AndAlso
                       catchBlock.CatchStatement.IdentifierName IsNot Nothing Then
                        _additionalTerms.Add(catchBlock.CatchStatement.IdentifierName.Identifier.ValueText)
                    End If
                End If
            End Sub
 
            Private Sub AddMeExpression()
                If Not InSharedContext() Then
                    _additionalTerms.Add("Me")
                End If
            End Sub
 
            Private Function InSharedContext() As Boolean
                Dim methodBlock = Me._parentStatement.GetAncestorOrThis(Of MethodBlockBaseSyntax)()
                If methodBlock IsNot Nothing AndAlso methodBlock.BlockStatement.Modifiers.Any(Function(t) t.Kind = SyntaxKind.SharedKeyword) Then
                    Return True ' // TODO: need to hit this with unit-tests
                End If
 
                Dim propertyBlock = Me._parentStatement.GetAncestorOrThis(Of PropertyBlockSyntax)()
                If propertyBlock IsNot Nothing AndAlso propertyBlock.PropertyStatement.Modifiers.Any(Function(t) t.Kind = SyntaxKind.SharedKeyword) Then
                    Return True ' // // TODO: need to hit this with unit-tests
                End If
 
                Dim typeBlock = Me._parentStatement.GetAncestorOrThis(Of TypeBlockSyntax)()
                If typeBlock IsNot Nothing AndAlso typeBlock.Kind = SyntaxKind.ModuleBlock Then
                    Return True
                End If
 
                Return False
            End Function
 
            Private Shared Sub AddExpressionTerms(e As ExpressionSyntax, terms As List(Of String))
                If e Is Nothing Then
                    Return
                End If
 
                terms.Add(e.ConvertToSingleLine().ToString())
            End Sub
        End Class
    End Class
End Namespace