File: ExtractMethod\VisualBasicMethodExtractor.Analyzer.vb
Web Access
Project: ..\..\..\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.ExtractMethod
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod
    Partial Friend Class VisualBasicMethodExtractor
        Inherits MethodExtractor
 
        Private Class VisualBasicAnalyzer
            Inherits Analyzer
 
            Private Shared ReadOnly s_nonNoisySyntaxKindSet As HashSet(Of Integer) = New HashSet(Of Integer) From {SyntaxKind.WhitespaceTrivia, SyntaxKind.EndOfLineTrivia}
 
            Public Shared Function AnalyzeResultAsync(currentSelectionResult As SelectionResult, cancellationToken As CancellationToken) As Task(Of AnalyzerResult)
                Dim analyzer = New VisualBasicAnalyzer(currentSelectionResult, cancellationToken)
                Return analyzer.AnalyzeAsync()
            End Function
 
            Public Sub New(currentSelectionResult As SelectionResult, cancellationToken As CancellationToken)
                MyBase.New(currentSelectionResult, localFunction:=False, cancellationToken)
            End Sub
 
            Protected Overrides Function CreateFromSymbol(
                compilation As Compilation, symbol As ISymbol,
                type As ITypeSymbol, style As VariableStyle, requiresDeclarationExpressionRewrite As Boolean) As VariableInfo
                If symbol.IsFunctionValue() AndAlso style.ParameterStyle.DeclarationBehavior <> DeclarationBehavior.None Then
                    Contract.ThrowIfFalse(style.ParameterStyle.DeclarationBehavior = DeclarationBehavior.MoveIn OrElse style.ParameterStyle.DeclarationBehavior = DeclarationBehavior.SplitIn)
                    style = AlwaysReturn(style)
                End If
 
                Return CreateFromSymbolCommon(Of LocalDeclarationStatementSyntax)(compilation, symbol, type, style, s_nonNoisySyntaxKindSet)
            End Function
 
            Protected Overrides Function GetIndexOfVariableInfoToUseAsReturnValue(variableInfo As IList(Of VariableInfo)) As Integer
                ' in VB, only byRef exist, not out or ref distinction like C#
                Dim numberOfByRefParameters = 0
 
                Dim byRefSymbolIndex As Integer = -1
 
                For i As Integer = 0 To variableInfo.Count - 1
                    Dim variable = variableInfo(i)
 
                    ' there should be no-one set as return value yet
                    Contract.ThrowIfTrue(variable.UseAsReturnValue)
 
                    If Not variable.CanBeUsedAsReturnValue Then
                        Continue For
                    End If
 
                    ' check modifier
                    If variable.ParameterModifier = ParameterBehavior.Ref OrElse
                       variable.ParameterModifier = ParameterBehavior.Out Then
                        numberOfByRefParameters += 1
                        byRefSymbolIndex = i
                    End If
                Next i
 
                ' if there is only one "byRef", that will be converted to return statement.
                If numberOfByRefParameters = 1 Then
                    Return byRefSymbolIndex
                End If
 
                Return -1
            End Function
 
            Protected Overrides Function GetRangeVariableType(semanticModel As SemanticModel, symbol As IRangeVariableSymbol) As ITypeSymbol
                Dim info = semanticModel.GetSpeculativeTypeInfo(Me.SelectionResult.FinalSpan.Start, SyntaxFactory.ParseName(symbol.Name), SpeculativeBindingOption.BindAsExpression)
                If info.Type.IsErrorType() Then
                    Return Nothing
                End If
 
                Return If(info.ConvertedType.IsObjectType(), info.ConvertedType, info.Type)
            End Function
 
            Protected Overrides Function GetFlowAnalysisNodeRange() As Tuple(Of SyntaxNode, SyntaxNode)
                Dim vbSelectionResult = DirectCast(Me.SelectionResult, VisualBasicSelectionResult)
 
                Dim firstStatement = vbSelectionResult.GetFirstStatement()
                Dim lastStatement = vbSelectionResult.GetLastStatement()
 
                ' single statement case
                If firstStatement Is lastStatement OrElse
                   firstStatement.Span.Contains(lastStatement.Span) Then
                    Return New Tuple(Of SyntaxNode, SyntaxNode)(firstStatement, firstStatement)
                End If
 
                ' multiple statement case
                Dim firstUnderContainer = vbSelectionResult.GetFirstStatementUnderContainer()
                Dim lastUnderContainer = vbSelectionResult.GetLastStatementUnderContainer()
                Return New Tuple(Of SyntaxNode, SyntaxNode)(firstUnderContainer, lastUnderContainer)
            End Function
 
            Protected Overrides Function ContainsReturnStatementInSelectedCode(jumpOutOfRegionStatements As IEnumerable(Of SyntaxNode)) As Boolean
                Return jumpOutOfRegionStatements.Where(Function(n) TypeOf n Is ReturnStatementSyntax OrElse TypeOf n Is ExitStatementSyntax).Any()
            End Function
 
            Protected Overrides Function ReadOnlyFieldAllowed() As Boolean
                Dim methodBlock = Me.SelectionResult.GetContainingScopeOf(Of MethodBlockBaseSyntax)()
                If methodBlock Is Nothing Then
                    Return True
                End If
 
                Return Not TypeOf methodBlock.BlockStatement Is SubNewStatementSyntax
            End Function
        End Class
    End Class
End Namespace