' 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 Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery ''' <summary> ''' A visitor that determines if the targetToken passed in the constructor can be considered ''' the end of the visited statement. Tokens in the token stream of the file after ''' targetToken are ignored. This means that in some cases, say "Throw" vs. "Throw x" there ''' is more than one keyword that could terminate the statement. ''' </summary> Friend Class IsStatementTerminatingTokenVisitor Inherits VisualBasicSyntaxVisitor(Of Boolean) Private ReadOnly _targetToken As SyntaxToken Public Sub New(targetToken As SyntaxToken) _targetToken = targetToken End Sub Public Overrides Function DefaultVisit(node As SyntaxNode) As Boolean ' By default, it doesn't terminate Return False End Function Public Overrides Function VisitAddRemoveHandlerStatement(node As AddRemoveHandlerStatementSyntax) As Boolean Return TargetTokenMatches(GetExpressionTerminatingToken(node.DelegateExpression)) End Function Public Overrides Function VisitAssignmentStatement(node As AssignmentStatementSyntax) As Boolean Return TargetTokenMatches(GetExpressionTerminatingToken(node.Right)) End Function Public Overrides Function VisitCallStatement(node As CallStatementSyntax) As Boolean Return TargetTokenMatches(GetExpressionTerminatingToken(node.Invocation)) End Function Public Overrides Function VisitExpressionStatement(node As ExpressionStatementSyntax) As Boolean Return TargetTokenMatches(GetExpressionTerminatingToken(node.Expression)) End Function Public Overrides Function VisitContinueStatement(node As ContinueStatementSyntax) As Boolean Return TargetTokenMatches(node.BlockKeyword) End Function Public Overrides Function VisitEraseStatement(node As EraseStatementSyntax) As Boolean Return TargetTokenMatches(GetExpressionTerminatingToken(node.Expressions.Last())) End Function Public Overrides Function VisitErrorStatement(node As ErrorStatementSyntax) As Boolean Return TargetTokenMatches(GetExpressionTerminatingToken(node.ErrorNumber)) End Function Public Overrides Function VisitExitStatement(node As ExitStatementSyntax) As Boolean Return TargetTokenMatches(node.BlockKeyword) End Function Public Overrides Function VisitGoToStatement(node As GoToStatementSyntax) As Boolean Return TargetTokenMatches(node.Label.LabelToken) End Function Public Overrides Function VisitLocalDeclarationStatement(node As LocalDeclarationStatementSyntax) As Boolean Dim lastDeclarator = node.Declarators.Last() If lastDeclarator.Initializer IsNot Nothing Then Return TargetTokenMatches(GetExpressionTerminatingToken(lastDeclarator.Initializer.Value)) ElseIf lastDeclarator.AsClause IsNot Nothing Then Return TargetTokenMatches(GetExpressionTerminatingToken(lastDeclarator.AsClause.Type)) Else Return TargetTokenMatches(lastDeclarator.Names.Last().Identifier) End If End Function Public Overrides Function VisitRaiseEventStatement(node As RaiseEventStatementSyntax) As Boolean Dim argumentList = node.ArgumentList If argumentList IsNot Nothing Then Return TargetTokenMatches(argumentList.CloseParenToken) Else Return TargetTokenMatches(node.Name.Identifier) End If End Function Public Overrides Function VisitReDimStatement(node As ReDimStatementSyntax) As Boolean Dim lastClause = node.Clauses.Last() If lastClause.ArrayBounds IsNot Nothing Then Return TargetTokenMatches(lastClause.ArrayBounds.CloseParenToken) Else Return TargetTokenMatches(GetExpressionTerminatingToken(lastClause.Expression)) End If End Function Public Overrides Function VisitResumeStatement(node As ResumeStatementSyntax) As Boolean If node.Label IsNot Nothing AndAlso TargetTokenMatches(node.Label.LabelToken) Then Return True End If Return TargetTokenMatches(node.ResumeKeyword) End Function Public Overrides Function VisitReturnStatement(node As Microsoft.CodeAnalysis.VisualBasic.Syntax.ReturnStatementSyntax) As Boolean ' Do we need a return value? Dim methodBlock = node.ReturnKeyword.GetAncestor(Of MethodBlockBaseSyntax) If methodBlock IsNot Nothing AndAlso methodBlock.IsKind(SyntaxKind.FunctionBlock, SyntaxKind.GetAccessorBlock) Then If node.Expression IsNot Nothing Then If TargetTokenMatches(GetExpressionTerminatingToken(node.Expression)) Then ' We are terminating the return value properly, so we're good Return True End If End If End If Return TargetTokenMatches(node.ReturnKeyword) End Function Public Overrides Function VisitStopOrEndStatement(node As StopOrEndStatementSyntax) As Boolean Return TargetTokenMatches(node.StopOrEndKeyword) End Function Public Overrides Function VisitThrowStatement(node As ThrowStatementSyntax) As Boolean If node.ThrowKeyword.HasAncestor(Of TryBlockSyntax)() Then If node.Expression IsNot Nothing Then If TargetTokenMatches(GetExpressionTerminatingToken(node.Expression)) Then Return True End If End If End If Return TargetTokenMatches(node.ThrowKeyword) End Function Private Function TargetTokenMatches(token As SyntaxToken) As Boolean Return token.Kind <> SyntaxKind.None AndAlso Not token.IsMissing AndAlso _targetToken = token End Function End Class End Namespace |