' 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.Runtime.CompilerServices Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Friend Module VisualBasicSyntaxTreeExtensions <Extension> Friend Function IsAccessibleEventContext(context As VisualBasicSyntaxContext, startAtEnclosingBaseType As Boolean) As Boolean If context.FollowsEndOfStatement Then Return False End If Dim targetToken = context.TargetToken If targetToken.IsChildToken(Of HandlesClauseSyntax)(Function(hc) hc.HandlesKeyword) OrElse targetToken.IsChildSeparatorToken(Function(hc As HandlesClauseSyntax) hc.Events) Then Dim container = context.EnclosingNamedType If container Is Nothing Then Return False End If If startAtEnclosingBaseType Then Return container.BaseType.GetAccessibleMembersInThisAndBaseTypes(Of IEventSymbol)(container).Any() End If Return container.GetAccessibleMembersInThisAndBaseTypes(Of IEventSymbol)(container).Any() End If Return False End Function <Extension()> Friend Function IsFollowingCompleteStatement(Of TParent As SyntaxNode)(context As VisualBasicSyntaxContext, childGetter As Func(Of TParent, StatementSyntax)) As Boolean Dim targetToken = context.TargetToken Dim parent = targetToken.GetAncestor(Of TParent)() If parent Is Nothing Then Return False End If Dim statement = childGetter(parent) If statement Is Nothing Then Return False End If Dim visitor As New IsStatementTerminatingTokenVisitor(targetToken) Return visitor.Visit(statement) End Function ''' <summary> ''' The specified position is immediately following a statement of one of the given kinds. ''' </summary> <Extension()> Friend Function IsAfterStatementOfKind(context As VisualBasicSyntaxContext, ParamArray kinds As SyntaxKind()) As Boolean If Not context.FollowsEndOfStatement Then Return False End If Dim targetToken = context.TargetToken If targetToken.Kind = SyntaxKind.None OrElse targetToken.Parent Is Nothing Then Return False End If Return targetToken.GetAncestor(Of StatementSyntax).IsKind(kinds) End Function <Extension()> Friend Function IsInStatementBlockOfKind(context As VisualBasicSyntaxContext, kind As SyntaxKind) As Boolean Return IsInStatementBlockHelper(context, Function(n, k) n.IsKind(k), kind) End Function <Extension()> Friend Function IsInStatementBlockOfKind(context As VisualBasicSyntaxContext, ParamArray kinds As SyntaxKind()) As Boolean Return IsInStatementBlockHelper(context, Function(n, k) n.IsKind(k), kinds) End Function Private Function IsInStatementBlockHelper(Of TArg)(context As VisualBasicSyntaxContext, predicate As Func(Of SyntaxNode, TArg, Boolean), arg As TArg) As Boolean Dim ancestor = context.TargetToken.Parent Do While ancestor IsNot Nothing If TypeOf ancestor Is EndBlockStatementSyntax Then ' If we're within the End Block, skip the block itself ancestor = ancestor.Parent.Parent If ancestor Is Nothing Then Return False End If End If If predicate(ancestor, arg) Then Return True End If If TypeOf ancestor Is LambdaExpressionSyntax Then If Not (context.FollowsEndOfStatement AndAlso context.TargetToken = ancestor.GetLastToken()) Then ' We should not look past lambdas Return False End If End If ancestor = ancestor.Parent Loop Return False End Function <Extension()> Public Function IsDelegateCreationContext(context As VisualBasicSyntaxContext) As Boolean If context.FollowsEndOfStatement Then Return False End If Dim token = context.TargetToken If token.Parent.IsKind(SyntaxKind.ArgumentList) AndAlso TypeOf token.Parent.Parent Is NewExpressionSyntax Then Dim symbolInfo = context.SemanticModel.GetSymbolInfo(DirectCast(token.Parent.Parent, NewExpressionSyntax).Type()) Dim objectCreationType = TryCast(symbolInfo.Symbol, ITypeSymbol) If objectCreationType IsNot Nothing AndAlso objectCreationType.TypeKind = TypeKind.Delegate Then Return True End If End If Return False End Function <Extension()> Public Function CanDeclareCustomEventAccessor(context As VisualBasicSyntaxContext, accessorBlockKind As SyntaxKind) As Boolean If context.IsCustomEventContext Then Dim accessors = context.TargetToken.GetAncestor(Of EventBlockSyntax)().Accessors Return Not accessors.Any(Function(a) a.IsKind(accessorBlockKind)) AndAlso Not accessors.Any(Function(a) a.Span.Contains(context.Position)) End If Return False End Function End Module End Namespace |