File: UseAutoProperty\VisualBasicUseAutoPropertyCodeFixProvider.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.Collections.Immutable
Imports System.Composition
Imports System.Diagnostics.CodeAnalysis
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.Formatting.Rules
Imports Microsoft.CodeAnalysis.Rename
Imports Microsoft.CodeAnalysis.UseAutoProperty
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty
    <ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.UseAutoProperty), [Shared]>
    Friend NotInheritable Class VisualBasicUseAutoPropertyCodeFixProvider
        Inherits AbstractUseAutoPropertyCodeFixProvider(Of VisualBasicUseAutoPropertyCodeFixProvider, TypeBlockSyntax, PropertyBlockSyntax, ModifiedIdentifierSyntax, ConstructorBlockSyntax, ExpressionSyntax)
 
        <ImportingConstructor>
        <SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification:="Used in test code: https://github.com/dotnet/roslyn/issues/42814")>
        Public Sub New()
        End Sub
 
        Protected Overrides Function GetPropertyDeclaration(node As SyntaxNode) As PropertyBlockSyntax
            If TypeOf node Is PropertyStatementSyntax Then
                node = node.Parent
            End If
 
            Return DirectCast(node, PropertyBlockSyntax)
        End Function
 
        Protected Overrides Function GetNodeToRemove(identifier As ModifiedIdentifierSyntax) As SyntaxNode
            Return Utilities.GetNodeToRemove(identifier)
        End Function
 
        Protected Overrides Function GetFormattingRules(document As Document, finalProperty As SyntaxNode) As ImmutableArray(Of AbstractFormattingRule)
            Return Nothing
        End Function
 
        Protected Overrides Function RewriteFieldReferencesInProperty([property] As PropertyBlockSyntax, fieldLocations As LightweightRenameLocations, cancellationToken As CancellationToken) As PropertyBlockSyntax
            ' Only called to rewrite to `field` (which VB does not support).
            Return [property]
        End Function
 
        Protected Overrides Async Function UpdatePropertyAsync(
                propertyDocument As Document,
                compilation As Compilation,
                fieldSymbol As IFieldSymbol,
                propertySymbol As IPropertySymbol,
                fieldDeclarator As ModifiedIdentifierSyntax,
                propertyDeclaration As PropertyBlockSyntax,
                isWrittenToOutsideOfConstructor As Boolean,
                isTrivialGetAccessor As Boolean,
                isTrivialSetAccessor As Boolean,
                cancellationToken As CancellationToken) As Task(Of SyntaxNode)
            Dim statement = propertyDeclaration.PropertyStatement
 
            Dim generator = SyntaxGenerator.GetGenerator(propertyDocument.Project)
            Dim canBeReadOnly = Not isWrittenToOutsideOfConstructor AndAlso Not propertyDeclaration.Accessors.Any(SyntaxKind.SetAccessorBlock)
 
            statement = DirectCast(generator.WithModifiers(statement, generator.GetModifiers(propertyDeclaration).WithIsReadOnly(canBeReadOnly)), PropertyStatementSyntax)
 
            Dim initializer = Await GetFieldInitializerAsync(fieldSymbol, cancellationToken).ConfigureAwait(False)
            If initializer.equalsValue IsNot Nothing Then
                statement = statement.WithTrailingTrivia(SyntaxFactory.Space) _
                    .WithInitializer(initializer.equalsValue) _
                    .WithTrailingTrivia(statement.GetTrailingTrivia.Where(Function(x) x.Kind <> SyntaxKind.EndOfLineTrivia)) _
                    .WithAppendedTrailingTrivia(initializer.equalsValue.GetTrailingTrivia())
            End If
 
            If initializer.asNewClause IsNot Nothing Then
                statement = statement.WithAsClause(initializer.asNewClause)
            End If
 
            If initializer.arrayBounds IsNot Nothing Then
                Dim semanticsModel = Await propertyDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
                Dim arrayType = TryCast(semanticsModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken).Type, IArrayTypeSymbol)
                If arrayType IsNot Nothing Then
                    Dim arrayCreation = SyntaxFactory.ArrayCreationExpression(
                    Nothing,
                    arrayType.ElementType.GenerateTypeSyntax(),
                    initializer.arrayBounds,
                    If(TryCast(initializer.equalsValue?.Value, CollectionInitializerSyntax), SyntaxFactory.CollectionInitializer()))
                    statement = statement.WithTrailingTrivia(SyntaxFactory.Space).
                                      WithInitializer(SyntaxFactory.EqualsValue(arrayCreation))
                End If
            End If
 
            Return statement
        End Function
 
        Private Shared Async Function GetFieldInitializerAsync(fieldSymbol As IFieldSymbol, cancellationToken As CancellationToken) As Task(Of (equalsValue As EqualsValueSyntax, asNewClause As AsNewClauseSyntax, arrayBounds As ArgumentListSyntax))
            Dim identifier = TryCast(Await fieldSymbol.DeclaringSyntaxReferences(0).GetSyntaxAsync(cancellationToken).ConfigureAwait(False), ModifiedIdentifierSyntax)
            Dim declarator = TryCast(identifier?.Parent, VariableDeclaratorSyntax)
            Dim initializer = declarator?.Initializer
            Dim arrayBounds = identifier?.ArrayBounds
 
            ' We are only interested in the AsClause if it's being used as an initializer:
            '  Dim x As String -- no need to preserve the clause since it will already be the same on the property
            '  Dim x As New Guid("...") -- need to preserve the clause since it's being used as an initializer
            Dim asNewClause = TryCast(declarator.AsClause, AsNewClauseSyntax)
            Return (initializer, asNewClause, arrayBounds)
        End Function
    End Class
End Namespace