File: ExtractMethod\VisualBasicMethodExtractor.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.ExtractMethod
Imports Microsoft.CodeAnalysis.Formatting.Rules
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod
    Partial Friend Class VisualBasicMethodExtractor
        Inherits MethodExtractor(Of VisualBasicSelectionResult, ExecutableStatementSyntax, ExpressionSyntax)
 
        Public Sub New(result As VisualBasicSelectionResult, options As ExtractMethodGenerationOptions)
            MyBase.New(result, options, localFunction:=False)
        End Sub
 
        Protected Overrides Function CreateCodeGenerator(analyzerResult As AnalyzerResult) As CodeGenerator
            Return VisualBasicCodeGenerator.Create(Me.OriginalSelectionResult, analyzerResult, Me.Options)
        End Function
 
        Protected Overrides Function Analyze(selectionResult As VisualBasicSelectionResult, localFunction As Boolean, cancellationToken As CancellationToken) As AnalyzerResult
            Return VisualBasicAnalyzer.AnalyzeResult(selectionResult, cancellationToken)
        End Function
 
        Protected Overrides Function GetInsertionPointNode(
                analyzerResult As AnalyzerResult, cancellationToken As CancellationToken) As SyntaxNode
            Dim document = Me.OriginalSelectionResult.SemanticDocument
            Dim originalSpanStart = OriginalSelectionResult.OriginalSpan.Start
            Contract.ThrowIfFalse(originalSpanStart >= 0)
 
            Dim root = document.Root
            Dim basePosition = root.FindToken(originalSpanStart)
 
            Dim enclosingTopLevelNode As SyntaxNode = basePosition.GetAncestor(Of PropertyBlockSyntax)()
            If enclosingTopLevelNode Is Nothing Then
                enclosingTopLevelNode = basePosition.GetAncestor(Of EventBlockSyntax)()
            End If
 
            If enclosingTopLevelNode Is Nothing Then
                enclosingTopLevelNode = basePosition.GetAncestor(Of MethodBlockBaseSyntax)()
            End If
 
            If enclosingTopLevelNode Is Nothing Then
                enclosingTopLevelNode = basePosition.GetAncestor(Of FieldDeclarationSyntax)()
            End If
 
            If enclosingTopLevelNode Is Nothing Then
                enclosingTopLevelNode = basePosition.GetAncestor(Of PropertyStatementSyntax)()
            End If
 
            Contract.ThrowIfNull(enclosingTopLevelNode)
            Return enclosingTopLevelNode
        End Function
 
        Protected Overrides Async Function PreserveTriviaAsync(selectionResult As VisualBasicSelectionResult, cancellationToken As CancellationToken) As Task(Of TriviaResult)
            Return Await VisualBasicTriviaResult.ProcessAsync(selectionResult, cancellationToken).ConfigureAwait(False)
        End Function
 
        Protected Overrides Function GenerateCodeAsync(insertionPoint As InsertionPoint, selectionResult As VisualBasicSelectionResult, analyzeResult As AnalyzerResult, options As ExtractMethodGenerationOptions, cancellationToken As CancellationToken) As Task(Of GeneratedCode)
            Return VisualBasicCodeGenerator.GenerateResultAsync(insertionPoint, selectionResult, analyzeResult, options, cancellationToken)
        End Function
 
        Protected Overrides Function GetCustomFormattingRule(document As Document) As AbstractFormattingRule
            Return FormattingRule.Instance
        End Function
 
        Protected Overrides Function GetInvocationNameToken(methodNames As IEnumerable(Of SyntaxToken)) As SyntaxToken?
            Return methodNames.FirstOrNull(Function(t) t.Parent.Kind <> SyntaxKind.SubStatement AndAlso t.Parent.Kind <> SyntaxKind.FunctionStatement)
        End Function
 
        Protected Overrides Function ParseTypeName(name As String) As SyntaxNode
            Return SyntaxFactory.ParseTypeName(name)
        End Function
 
        Private NotInheritable Class FormattingRule
            Inherits CompatAbstractFormattingRule
 
            Public Shared ReadOnly Instance As New FormattingRule()
 
            Private Sub New()
            End Sub
 
            Public Overrides Function GetAdjustNewLinesOperationSlow(ByRef previousToken As SyntaxToken, ByRef currentToken As SyntaxToken, ByRef nextOperation As NextGetAdjustNewLinesOperation) As AdjustNewLinesOperation
                If Not previousToken.IsLastTokenOfStatement() Then
                    Return nextOperation.Invoke(previousToken, currentToken)
                End If
 
                ' between [generated code] and [existing code]
                If Not CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(previousToken, currentToken) Then
                    Return nextOperation.Invoke(previousToken, currentToken)
                End If
 
                ' make sure attribute and previous statement has at least 1 blank lines between them
                If IsLessThanInAttribute(currentToken) Then
                    Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines)
                End If
 
                ' make sure previous statement and next type has at least 1 blank lines between them
                If TypeOf currentToken.Parent Is TypeStatementSyntax AndAlso
                   currentToken.Parent.GetFirstToken(includeZeroWidth:=True) = currentToken Then
                    Return FormattingOperations.CreateAdjustNewLinesOperation(2, AdjustNewLinesOption.ForceLines)
                End If
 
                Return nextOperation.Invoke(previousToken, currentToken)
            End Function
 
            Private Shared Function IsLessThanInAttribute(token As SyntaxToken) As Boolean
                ' < in attribute
                If token.Kind = SyntaxKind.LessThanToken AndAlso
                   token.Parent.Kind = SyntaxKind.AttributeList AndAlso
                   DirectCast(token.Parent, AttributeListSyntax).LessThanToken.Equals(token) Then
                    Return True
                End If
 
                Return False
            End Function
        End Class
 
        Protected Overrides Function InsertNewLineBeforeLocalFunctionIfNecessaryAsync(
                document As Document,
                invocationNameToken? As SyntaxToken,
                methodDefinition As SyntaxNode,
                cancellationToken As CancellationToken) As Task(Of (document As Document, invocationNameToken As SyntaxToken?))
            ' VB doesn't need to do any correction, so we just return the values untouched
            Return Task.FromResult((document, invocationNameToken))
        End Function
    End Class
End Namespace