File: src\Analyzers\VisualBasic\CodeFixes\GenerateConstructor\VisualBasicGenerateConstructorService.vb
Web Access
Project: src\src\CodeStyle\VisualBasic\CodeFixes\Microsoft.CodeAnalysis.VisualBasic.CodeStyle.Fixes.vbproj (Microsoft.CodeAnalysis.VisualBasic.CodeStyle.Fixes)
' 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.Collections.Immutable
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles
Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.Utilities
 
Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor
    <ExportLanguageService(GetType(IGenerateConstructorService), LanguageNames.VisualBasic), [Shared]>
    Partial Friend Class VisualBasicGenerateConstructorService
        Inherits AbstractGenerateConstructorService(Of VisualBasicGenerateConstructorService, ExpressionSyntax)
 
        <ImportingConstructor>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New()
        End Sub
 
        Protected Overrides Function IsImplicitObjectCreation(document As SemanticDocument, node As SyntaxNode, cancellationToken As CancellationToken) As Boolean
            Return False
        End Function
 
        Protected Overrides Function TryInitializeImplicitObjectCreation(document As SemanticDocument, node As SyntaxNode, cancellationToken As CancellationToken, ByRef token As SyntaxToken, ByRef arguments As ImmutableArray(Of Argument), ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
            token = Nothing
            arguments = Nothing
            typeToGenerateIn = Nothing
            Return False
        End Function
 
        Protected Overrides Function ContainingTypesOrSelfHasUnsafeKeyword(containingType As INamedTypeSymbol) As Boolean
            Return False
        End Function
 
        Protected Overrides Function GenerateNameForExpression(semanticModel As SemanticModel, expression As ExpressionSyntax, cancellationToken As CancellationToken) As String
            Return semanticModel.GenerateNameForExpression(expression, capitalize:=False, cancellationToken)
        End Function
 
        Protected Overrides Function GetArgumentType(
                semanticModel As SemanticModel,
                argument As Argument,
                cancellationToken As CancellationToken) As ITypeSymbol
            Return argument.Expression.DetermineType(semanticModel, cancellationToken)
        End Function
 
        Protected Overrides Function IsConstructorInitializerGeneration(document As SemanticDocument, node As SyntaxNode, cancellationToken As CancellationToken) As Boolean
            Return TypeOf node Is SimpleNameSyntax AndAlso
                TryCast(node.Parent, MemberAccessExpressionSyntax).IsConstructorInitializer() AndAlso
                node.Parent.Parent.Kind = SyntaxKind.InvocationExpression
        End Function
 
        Protected Overrides Function TryInitializeConstructorInitializerGeneration(
                document As SemanticDocument,
                node As SyntaxNode,
                cancellationToken As CancellationToken,
                ByRef token As SyntaxToken,
                ByRef arguments As ImmutableArray(Of Argument),
                ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
            Dim simpleName = DirectCast(node, SimpleNameSyntax)
            Dim memberAccess = DirectCast(simpleName.Parent, MemberAccessExpressionSyntax)
            Dim invocation = DirectCast(memberAccess.Parent, InvocationExpressionSyntax)
            If invocation.ArgumentList IsNot Nothing AndAlso Not invocation.ArgumentList.CloseParenToken.IsMissing Then
                Dim semanticModel = document.SemanticModel
                Dim containingType = semanticModel.GetEnclosingNamedType(simpleName.SpanStart, cancellationToken)
 
                If containingType IsNot Nothing Then
                    token = simpleName.Identifier
                    arguments = GetArguments(invocation.ArgumentList.Arguments)
                    typeToGenerateIn = If(memberAccess.Expression.IsKind(SyntaxKind.MyBaseExpression),
                                          containingType.BaseType,
                                          containingType)
 
                    Return typeToGenerateIn IsNot Nothing
                End If
            End If
 
            token = Nothing
            arguments = Nothing
            typeToGenerateIn = Nothing
            Return False
        End Function
 
        Protected Overrides Function IsSimpleNameGeneration(document As SemanticDocument, node As SyntaxNode, cancellationToken As CancellationToken) As Boolean
            Return TypeOf node Is SimpleNameSyntax
        End Function
 
        Protected Overrides Function TryInitializeSimpleNameGenerationState(
                document As SemanticDocument,
                node As SyntaxNode,
                cancellationToken As CancellationToken,
                ByRef token As SyntaxToken,
                ByRef arguments As ImmutableArray(Of Argument),
                ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
 
            Dim simpleName = DirectCast(node, SimpleNameSyntax)
            Dim name = If(simpleName.IsRightSideOfQualifiedName(), DirectCast(simpleName.Parent, NameSyntax), simpleName)
 
            If TypeOf name.Parent Is ObjectCreationExpressionSyntax Then
                Dim objectCreationExpression = DirectCast(name.Parent, ObjectCreationExpressionSyntax)
 
                If objectCreationExpression.ArgumentList IsNot Nothing AndAlso
                   Not objectCreationExpression.ArgumentList.CloseParenToken.IsMissing Then
 
                    Dim semanticModel = document.SemanticModel
 
                    token = simpleName.Identifier
                    arguments = GetArguments(objectCreationExpression.ArgumentList.Arguments)
 
                    Dim symbolInfo = semanticModel.GetSymbolInfo(objectCreationExpression.Type, cancellationToken)
                    typeToGenerateIn = TryCast(symbolInfo.GetAnySymbol(), INamedTypeSymbol)
 
                    Return typeToGenerateIn IsNot Nothing
                End If
            End If
 
            token = Nothing
            arguments = Nothing
            typeToGenerateIn = Nothing
            Return False
        End Function
 
        Protected Overrides Function TryInitializeSimpleAttributeNameGenerationState(
                document As SemanticDocument,
                node As SyntaxNode,
                cancellationToken As CancellationToken,
                ByRef token As SyntaxToken,
                ByRef arguments As ImmutableArray(Of Argument),
                ByRef typeToGenerateIn As INamedTypeSymbol) As Boolean
 
            Dim simpleName = DirectCast(node, SimpleNameSyntax)
            Dim name = If(simpleName.IsRightSideOfQualifiedName(), DirectCast(simpleName.Parent, NameSyntax), simpleName)
 
            If TypeOf name.Parent Is AttributeSyntax Then
                Dim attribute = DirectCast(name.Parent, AttributeSyntax)
 
                If attribute.ArgumentList IsNot Nothing AndAlso
                   Not attribute.ArgumentList.CloseParenToken.IsMissing Then
 
                    Dim symbolInfo = document.SemanticModel.GetSymbolInfo(attribute, cancellationToken)
                    If symbolInfo.CandidateReason = CandidateReason.OverloadResolutionFailure AndAlso Not symbolInfo.CandidateSymbols.IsEmpty Then
                        token = simpleName.Identifier
                        arguments = GetArguments(attribute.ArgumentList.Arguments)
                        typeToGenerateIn = TryCast(symbolInfo.CandidateSymbols.FirstOrDefault().ContainingSymbol, INamedTypeSymbol)
 
                        Return typeToGenerateIn IsNot Nothing
                    End If
                End If
            End If
 
            token = Nothing
            arguments = Nothing
            typeToGenerateIn = Nothing
            Return False
        End Function
 
        Private Shared Function GetArguments(arguments As SeparatedSyntaxList(Of ArgumentSyntax)) As ImmutableArray(Of Argument)
            Return arguments.SelectAsArray(Function(a) New Argument(RefKind.None, TryCast(a, SimpleArgumentSyntax)?.NameColonEquals?.Name.Identifier.ValueText, a.GetArgumentExpression()))
        End Function
 
        Protected Overrides Function IsConversionImplicit(compilation As Compilation, sourceType As ITypeSymbol, targetType As ITypeSymbol) As Boolean
            Return compilation.ClassifyConversion(sourceType, targetType).IsWidening
        End Function
 
        Protected Overrides Function GetCurrentConstructor(semanticModel As SemanticModel, token As SyntaxToken, cancellationToken As CancellationToken) As IMethodSymbol
            Dim subNewStatement = token.GetAncestor(Of ConstructorBlockSyntax)()?.SubNewStatement
            Return If(subNewStatement IsNot Nothing, semanticModel.GetDeclaredSymbol(subNewStatement, cancellationToken), Nothing)
        End Function
 
        Protected Overrides Function GetDelegatedConstructor(semanticModel As SemanticModel, constructor As IMethodSymbol, cancellationToken As CancellationToken) As IMethodSymbol
            Dim constructorStatements = constructor.DeclaringSyntaxReferences(0).GetSyntax(cancellationToken).Parent.GetStatements()
            If (constructorStatements.IsEmpty()) Then
                Return Nothing
            End If
 
            Dim constructorInitializerSyntax = constructorStatements(0)
            Dim expressionStatement = TryCast(constructorInitializerSyntax, ExpressionStatementSyntax)
            If (expressionStatement IsNot Nothing AndAlso expressionStatement.Expression.IsKind(SyntaxKind.InvocationExpression)) Then
                Dim methodSymbol = TryCast(semanticModel.GetSymbolInfo(expressionStatement.Expression, cancellationToken).Symbol, IMethodSymbol)
                Return If(methodSymbol IsNot Nothing AndAlso methodSymbol.MethodKind = MethodKind.Constructor, methodSymbol, Nothing)
            End If
 
            Return Nothing
        End Function
    End Class
End Namespace