/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/EditorFeatures/VisualBasic/EndConstructGeneration/EndConstructStatementVisitor.vb
325 строк
16 KB
Cyrus Najmabadi
Make more code jtf
19 дек 2024, 00:34
19 дек 2024, 00:34
f88627a
Код
Авторство
О чём код?
' 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.Text Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.EndConstructGeneration Partial Friend NotInheritable Class EndConstructStatementVisitor Inherits VisualBasicSyntaxVisitor(Of AbstractEndConstructResult) Private ReadOnly _textView As ITextView Private ReadOnly _subjectBuffer As ITextBuffer Private ReadOnly _state As EndConstructState Private ReadOnly _cancellationToken As CancellationToken ''' <summary> ''' Note: this is only passed in when <see cref="NeedsSemanticModel"/> return true. Any functions that require ''' a semantic model must declare their need up front so we do not pay the cost for semantics for all the cases ''' that do not need it. ''' </summary> Private ReadOnly _semanticModel As SemanticModel Public Sub New( textView As ITextView, subjectBuffer As ITextBuffer, state As EndConstructState, semanticModel As SemanticModel, cancellationToken As CancellationToken) _textView = textView _subjectBuffer = subjectBuffer _state = state _semanticModel = semanticModel _cancellationToken = cancellationToken End Sub Public Shared Function NeedsSemanticModel(node As SyntaxNode) As Boolean ' All of these call HandleMethodBlockSyntax, which needs semantics If TypeOf node Is MethodStatementSyntax OrElse TypeOf node Is SubNewStatementSyntax OrElse TypeOf node Is OperatorStatementSyntax Then Return True End If ' Calls GenerateAddOrRemoveHandler and GenerateRaiseEventHandler, both which needs semantics If TypeOf node Is EventStatementSyntax Then Return True End If Return False End Function Public Overrides Function VisitDoStatement(node As DoStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of DoLoopBlockSyntax)().Any(Function(block) block.LoopStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "Loop"}) Else Return Nothing End If End Function Public Overrides Function VisitEnumStatement(node As EnumStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of EnumBlockSyntax)().Any(Function(block) block.EndEnumStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End " & node.EnumKeyword.ToString()}) Else Return Nothing End If End Function Public Overrides Function VisitForStatement(node As ForStatementSyntax) As AbstractEndConstructResult Return TryApplyOnForStatement(node) End Function Public Overrides Function VisitForEachStatement(node As ForEachStatementSyntax) As AbstractEndConstructResult Return TryApplyOnForStatement(node) End Function ''' <param name="forStatement">The ForStatementSyntax or ForEachStatementSyntax for the loop.</param> Public Function TryApplyOnForStatement(forStatement As StatementSyntax) As AbstractEndConstructResult Dim needsEnd = False For Each parent In forStatement.GetAncestorsOrThis(Of ForOrForEachBlockSyntax)() If parent.NextStatement Is Nothing Then ' For Blocks may have a null EndOpt, which indicates that they were closed by a parent block's Next ' statement. Thus this block is closed, and we are done Return Nothing ElseIf parent.NextStatement.ControlVariables.Count > 0 Then ' The parser has matched start/end blocks, and so anything within this we consider as done Return Nothing ElseIf parent.NextStatement.IsMissing Then needsEnd = True End If Next If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(forStatement.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "Next"}) Else Return Nothing End If End Function Private Function HandleMethodBlockSyntax(methodBlock As MethodBlockBaseSyntax) As AbstractEndConstructResult If methodBlock IsNot Nothing AndAlso methodBlock.EndBlockStatement.IsMissing Then Dim result = TryGenerateResultForConstructorSpitWithInitializeComponent(methodBlock) If result IsNot Nothing Then Return result End If Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(methodBlock.BlockStatement.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End " & methodBlock.BlockStatement.DeclarationKeyword.ToString()}) Else Return Nothing End If End Function Private Function TryGenerateResultForConstructorSpitWithInitializeComponent( methodBlock As MethodBlockBaseSyntax) As AbstractEndConstructResult If methodBlock.BlockStatement.Kind = SyntaxKind.SubNewStatement Then Dim boundConstructor = _semanticModel.GetDeclaredSymbol(DirectCast(methodBlock.BlockStatement, SubNewStatementSyntax)) If boundConstructor IsNot Nothing Then If boundConstructor.ContainingType.IsDesignerGeneratedTypeWithInitializeComponent(_semanticModel.Compilation) Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(methodBlock.BlockStatement.SpanStart) Dim innerAligningWhitespace = aligningWhitespace & " " ' When sticking on the comments, we don't want the ' in the localized string ' lest we try localizing the comment character itself Return New SpitLinesResult( { "", innerAligningWhitespace & "' " & VBEditorResources.This_call_is_required_by_the_designer, innerAligningWhitespace & "InitializeComponent()", "", innerAligningWhitespace & "' " & VBEditorResources.Add_any_initialization_after_the_InitializeComponent_call, "", aligningWhitespace & "End Sub" }) End If End If End If Return Nothing End Function Public Overrides Function VisitMethodStatement(node As MethodStatementSyntax) As AbstractEndConstructResult Dim blockToClose = node.GetAncestor(Of MethodBlockSyntax)() Return HandleMethodBlockSyntax(blockToClose) End Function Public Overrides Function VisitSubNewStatement(node As SubNewStatementSyntax) As AbstractEndConstructResult Dim blockToClose = node.GetAncestor(Of ConstructorBlockSyntax)() Return HandleMethodBlockSyntax(blockToClose) End Function Public Overrides Function VisitOperatorStatement(node As OperatorStatementSyntax) As AbstractEndConstructResult Dim blockToClose = node.GetAncestor(Of OperatorBlockSyntax)() Return HandleMethodBlockSyntax(blockToClose) End Function Public Overrides Function VisitNamespaceStatement(node As NamespaceStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of NamespaceBlockSyntax)().Any(Function(block) block.EndNamespaceStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End Namespace"}) Else Return Nothing End If End Function Public Overrides Function VisitSelectStatement(node As SelectStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of SelectBlockSyntax)().Any(Function(block) block.EndSelectStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Dim stringBuilder As New StringBuilder stringBuilder.Append(_textView.Options.GetNewLineCharacter()) stringBuilder.Append(aligningWhitespace & " Case ") Dim finalCaretPoint = stringBuilder.Length stringBuilder.AppendLine() stringBuilder.Append(aligningWhitespace & "End Select") Return New ReplaceSpanResult(New SnapshotSpan(_subjectBuffer.CurrentSnapshot, _state.CaretPosition, 0), stringBuilder.ToString(), newCaretPosition:=finalCaretPoint) Else Return (Nothing) End If End Function Public Overrides Function VisitSyncLockStatement(node As SyncLockStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of SyncLockBlockSyntax)().Any(Function(block) block.EndSyncLockStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End SyncLock"}) Else Return Nothing End If End Function Public Overrides Function VisitTryStatement(node As TryStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of TryBlockSyntax)().Any(Function(block) block.EndTryStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "Catch ex As Exception", "", aligningWhitespace & "End Try"}) Else Return Nothing End If End Function Public Overrides Function VisitModuleStatement(ByVal node As ModuleStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of ModuleBlockSyntax)().Any(Function(block) block.EndBlockStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End Module"}) Else Return Nothing End If End Function Public Overrides Function VisitClassStatement(ByVal node As ClassStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of ClassBlockSyntax)().Any(Function(block) block.EndBlockStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End Class"}) Else Return Nothing End If End Function Public Overrides Function VisitStructureStatement(ByVal node As StructureStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of StructureBlockSyntax)().Any(Function(block) block.EndBlockStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End Structure"}) Else Return Nothing End If End Function Public Overrides Function VisitInterfaceStatement(ByVal node As InterfaceStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of InterfaceBlockSyntax)().Any(Function(block) block.EndBlockStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End Interface"}) Else Return Nothing End If End Function Public Overrides Function VisitUsingStatement(ByVal node As UsingStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of UsingBlockSyntax)().Any(Function(block) block.EndUsingStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End Using"}) Else Return Nothing End If End Function Public Overrides Function VisitWhileStatement(node As WhileStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of WhileBlockSyntax)().Any(Function(block) block.EndWhileStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End While"}) Else Return Nothing End If End Function Public Overrides Function VisitWithStatement(node As WithStatementSyntax) As AbstractEndConstructResult Dim needsEnd = node.GetAncestorsOrThis(Of WithBlockSyntax)().Any(Function(block) block.EndWithStatement.IsMissing) If needsEnd Then Dim aligningWhitespace = _subjectBuffer.CurrentSnapshot.GetAligningWhitespace(node.SpanStart) Return New SpitLinesResult({"", aligningWhitespace & "End With"}) Else Return Nothing End If End Function Public Overrides Function VisitIfDirectiveTrivia(directive As IfDirectiveTriviaSyntax) As AbstractEndConstructResult Dim matchingDirectives = directive.GetMatchingConditionalDirectives(_cancellationToken) Dim needsEnd = Not matchingDirectives.Any(Function(d) d.Kind = SyntaxKind.EndIfDirectiveTrivia) If needsEnd Then Return New SpitLinesResult({"", "#End If"}) Else Return Nothing End If End Function Public Overrides Function VisitRegionDirectiveTrivia(directive As RegionDirectiveTriviaSyntax) As AbstractEndConstructResult Dim precedingRegionDirectives = directive.SyntaxTree.GetStartDirectives(_cancellationToken). Where(Function(d) d.SpanStart <= directive.SpanStart) If precedingRegionDirectives.Any(Function(d) d.GetMatchingStartOrEndDirective(_cancellationToken) Is Nothing) Then Return New SpitLinesResult({"", "#End Region"}) Else Return Nothing End If End Function End Class End Namespace