File: GenerateMember\GenerateVariable\VisualBasicGenerateVariableService.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.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.GenerateMember.GenerateVariable
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateVariable
    <ExportLanguageService(GetType(IGenerateVariableService), LanguageNames.VisualBasic), [Shared]>
    Partial Friend Class VisualBasicGenerateVariableService
        Inherits AbstractGenerateVariableService(Of VisualBasicGenerateVariableService, SimpleNameSyntax, ExpressionSyntax)
 
        <ImportingConstructor>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New()
        End Sub
 
        Protected Overrides Function IsExplicitInterfaceGeneration(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean
            Return TypeOf node Is QualifiedNameSyntax
        End Function
 
        Protected Overrides Function IsIdentifierNameGeneration(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean
            Return TypeOf node Is IdentifierNameSyntax
        End Function
 
        Protected Overrides Function TryInitializeExplicitInterfaceState(
                document As SemanticDocument, node As SyntaxNode, cancellationToken As CancellationToken,
                ByRef identifierToken As SyntaxToken, ByRef propertySymbol As IPropertySymbol, ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
            Dim qualifiedName = DirectCast(node, QualifiedNameSyntax)
            identifierToken = qualifiedName.Right.Identifier
 
            If qualifiedName.IsParentKind(SyntaxKind.ImplementsClause) Then
 
                Dim implementsClause = DirectCast(qualifiedName.Parent, ImplementsClauseSyntax)
                If implementsClause.IsParentKind(SyntaxKind.PropertyStatement) OrElse
                   implementsClause.IsParentKind(SyntaxKind.PropertyBlock) Then
 
                    Dim propertyBlock = TryCast(implementsClause.Parent, PropertyBlockSyntax)
                    Dim propertyNode = If(implementsClause.IsParentKind(SyntaxKind.PropertyStatement),
                                          DirectCast(implementsClause.Parent, PropertyStatementSyntax),
                                          propertyBlock.PropertyStatement)
 
                    Dim semanticModel = document.SemanticModel
 
                    propertySymbol = DirectCast(semanticModel.GetDeclaredSymbol(propertyNode, cancellationToken), IPropertySymbol)
                    If propertySymbol IsNot Nothing AndAlso Not propertySymbol.ExplicitInterfaceImplementations.Any() Then
 
                        Dim info = semanticModel.GetTypeInfo(qualifiedName.Left, cancellationToken)
                        typeToGenerateIn = TryCast(info.Type, INamedTypeSymbol)
                        Return typeToGenerateIn IsNot Nothing
                    End If
                End If
            End If
 
            identifierToken = Nothing
            propertySymbol = Nothing
            typeToGenerateIn = Nothing
            Return False
        End Function
 
        Protected Overrides Function TryInitializeIdentifierNameState(
                document As SemanticDocument, identifierName As SimpleNameSyntax,
                cancellationToken As CancellationToken,
                ByRef identifierToken As SyntaxToken,
                ByRef simpleNameOrMemberAccessExpression As ExpressionSyntax,
                ByRef isInExecutableBlock As Boolean,
                ByRef isConditionalAccessExpression As Boolean) As Boolean
            identifierToken = identifierName.Identifier
 
            Dim memberAccess = TryCast(identifierName.Parent, MemberAccessExpressionSyntax)
            If memberAccess IsNot Nothing Then
                If memberAccess.Kind = SyntaxKind.DictionaryAccessExpression Then
                    Return False
                End If
            End If
 
            Dim conditionalMemberAccess = TryCast(identifierName.Parent.Parent, ConditionalAccessExpressionSyntax)
 
            If memberAccess?.Name Is identifierName Then
                simpleNameOrMemberAccessExpression = DirectCast(memberAccess, ExpressionSyntax)
            ElseIf TryCast(conditionalMemberAccess?.WhenNotNull, MemberAccessExpressionSyntax)?.Name Is identifierName Then
                simpleNameOrMemberAccessExpression = conditionalMemberAccess
            Else
                simpleNameOrMemberAccessExpression = identifierName
            End If
 
            Dim semanticModel = document.SemanticModel
            If Not IsLegal(semanticModel, simpleNameOrMemberAccessExpression, cancellationToken) AndAlso
               Not simpleNameOrMemberAccessExpression.Parent.IsKind(SyntaxKind.NameOfExpression, SyntaxKind.NamedFieldInitializer) Then
                identifierToken = Nothing
                isConditionalAccessExpression = Nothing
                simpleNameOrMemberAccessExpression = Nothing
                Return False
            End If
 
            Dim block = identifierToken.Parent.GetContainingMultiLineExecutableBlocks().FirstOrDefault()
            isInExecutableBlock = block IsNot Nothing AndAlso Not block.OverlapsHiddenPosition(cancellationToken)
            isConditionalAccessExpression = conditionalMemberAccess IsNot Nothing
            Return True
        End Function
 
        Private Shared Function IsLegal(semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As Boolean
            Dim tree = semanticModel.SyntaxTree
            Dim position = expression.SpanStart
 
            If Not tree.IsExpressionContext(position, cancellationToken) AndAlso
               Not tree.IsSingleLineStatementContext(position, cancellationToken) Then
                Return False
            End If
 
            Return expression.CanReplaceWithLValue(semanticModel, cancellationToken)
        End Function
 
        Protected Overrides Function TryConvertToLocalDeclaration(type As ITypeSymbol, identifierToken As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken, ByRef newRoot As SyntaxNode) As Boolean
            Return False
        End Function
    End Class
End Namespace