|
' 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
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
Partial Friend Module MemberAccessExpressionSyntaxExtensions
<Extension()>
Public Function IsConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean
Return memberAccess.IsThisConstructorInitializer() OrElse memberAccess.IsBaseConstructorInitializer()
End Function
<Extension()>
Public Function IsThisConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean
If memberAccess IsNot Nothing Then
If IsFirstStatementInConstructor(memberAccess) Then
If memberAccess.Expression.IsKind(SyntaxKind.MeExpression) OrElse
memberAccess.Expression.IsKind(SyntaxKind.MyClassExpression) Then
If memberAccess.Name.IsKind(SyntaxKind.IdentifierName) Then
Return memberAccess.Name.Identifier.HasMatchingText(SyntaxKind.NewKeyword)
End If
End If
End If
End If
Return False
End Function
<Extension()>
Public Function IsBaseConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean
If memberAccess IsNot Nothing Then
If IsFirstStatementInConstructor(memberAccess) Then
If memberAccess.Expression.IsKind(SyntaxKind.MyBaseExpression) Then
If memberAccess.Name.IsKind(SyntaxKind.IdentifierName) Then
Return memberAccess.Name.Identifier.HasMatchingText(SyntaxKind.NewKeyword)
End If
End If
End If
End If
Return False
End Function
Private Function IsFirstStatementInConstructor(memberAccess As MemberAccessExpressionSyntax) As Boolean
Dim isCall As Boolean
Dim statement As SyntaxNode
If TypeOf memberAccess.Parent Is InvocationExpressionSyntax Then
statement = memberAccess.Parent.Parent
isCall = statement IsNot Nothing AndAlso (statement.Kind = SyntaxKind.CallStatement OrElse statement.Kind = SyntaxKind.ExpressionStatement)
Else
statement = memberAccess.Parent
isCall = statement.IsKind(SyntaxKind.CallStatement)
End If
If isCall Then
Return statement.IsParentKind(SyntaxKind.ConstructorBlock) AndAlso
DirectCast(statement.Parent, ConstructorBlockSyntax).Statements.First() Is statement
End If
Return False
End Function
<Extension>
Public Function GetExpressionOfMemberAccessExpression(
memberAccessExpression As MemberAccessExpressionSyntax,
Optional allowImplicitTarget As Boolean = False) As ExpressionSyntax
If memberAccessExpression Is Nothing Then
Return Nothing
End If
If memberAccessExpression.Expression IsNot Nothing Then
Return memberAccessExpression.Expression
End If
' we have a member access expression with a null expression, this may be one of the
' following forms:
'
' 1) new With { .a = 1, .b = .a <-- .a refers to the anonymous type
' 2) With obj : .m <-- .m refers to the obj type
' 3) new T() With { .a = 1, .b = .a <-- 'a refers to the T type
If allowImplicitTarget Then
Dim conditional = memberAccessExpression.GetRootConditionalAccessExpression()
If conditional IsNot Nothing Then
If conditional.Expression Is Nothing Then
' No expression, maybe we're in a with block
Dim withBlock = conditional.GetAncestor(Of WithBlockSyntax)()
If withBlock IsNot Nothing Then
Return withBlock.WithStatement.Expression
End If
End If
Return conditional.Expression
End If
Dim current As SyntaxNode = memberAccessExpression
While current IsNot Nothing
If TypeOf current Is AnonymousObjectCreationExpressionSyntax Then
Return DirectCast(current, ExpressionSyntax)
ElseIf TypeOf current Is WithBlockSyntax Then
Dim withBlock = DirectCast(current, WithBlockSyntax)
If memberAccessExpression IsNot withBlock.WithStatement.Expression Then
Return withBlock.WithStatement.Expression
End If
ElseIf TypeOf current Is ObjectMemberInitializerSyntax AndAlso
TypeOf current.Parent Is ObjectCreationExpressionSyntax Then
Return DirectCast(current.Parent, ExpressionSyntax)
End If
current = current.Parent
End While
End If
Return Nothing
End Function
End Module
End Namespace
|