/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/VisualBasic/Portable/ReplacePropertyWithMethods/VisualBasicReplacePropertyWithMethods.vb
254 строки
13 KB
Tomáš Matoušek
Remove fallbacks (#74041)
09 июл 2024, 23:35
Не верифицирован
09 июл 2024, 23:35
6ceee07
Код
Авторство
О чём код?
' 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.CodeGeneration Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.ReplacePropertyWithMethods Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.ReplaceMethodWithProperty <ExportLanguageService(GetType(IReplacePropertyWithMethodsService), LanguageNames.VisualBasic), [Shared]> Partial Friend Class VisualBasicReplacePropertyWithMethods Inherits AbstractReplacePropertyWithMethodsService(Of IdentifierNameSyntax, ExpressionSyntax, CrefReferenceSyntax, StatementSyntax, PropertyStatementSyntax) <ImportingConstructor> <Obsolete(MefConstruction.ImportingConstructorMessage, True)> Public Sub New() End Sub Public Overrides Function GetReplacementMembersAsync( document As Document, [property] As IPropertySymbol, propertyDeclarationNode As SyntaxNode, propertyBackingField As IFieldSymbol, desiredGetMethodName As String, desiredSetMethodName As String, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of SyntaxNode)) Dim propertyStatement = TryCast(propertyDeclarationNode, PropertyStatementSyntax) If propertyStatement Is Nothing Then Return SpecializedTasks.EmptyImmutableArray(Of SyntaxNode) End If Return Task.FromResult(ConvertPropertyToMembers( SyntaxGenerator.GetGenerator(document), [property], propertyStatement, propertyBackingField, desiredGetMethodName, desiredSetMethodName, cancellationToken)) End Function Private Shared Function ConvertPropertyToMembers( generator As SyntaxGenerator, [property] As IPropertySymbol, propertyStatement As PropertyStatementSyntax, propertyBackingField As IFieldSymbol, desiredGetMethodName As String, desiredSetMethodName As String, cancellationToken As CancellationToken) As ImmutableArray(Of SyntaxNode) Dim result = ArrayBuilder(Of SyntaxNode).GetInstance() If propertyBackingField IsNot Nothing Then Dim initializer = propertyStatement.Initializer?.Value result.Add(generator.FieldDeclaration(propertyBackingField, initializer)) End If Dim getMethod = [property].GetMethod If getMethod IsNot Nothing Then result.Add(GetGetMethod( generator, [property], propertyStatement, propertyBackingField, getMethod, desiredGetMethodName, cancellationToken:=cancellationToken)) End If Dim setMethod = [property].SetMethod If setMethod IsNot Nothing Then result.Add(GetSetMethod( generator, [property], propertyStatement, propertyBackingField, setMethod, desiredSetMethodName, cancellationToken:=cancellationToken)) End If Return result.ToImmutableAndFree() End Function Private Shared Function GetGetMethod( generator As SyntaxGenerator, [property] As IPropertySymbol, propertyStatement As PropertyStatementSyntax, propertyBackingField As IFieldSymbol, getMethod As IMethodSymbol, desiredGetMethodName As String, cancellationToken As CancellationToken) As SyntaxNode Dim statements = New List(Of SyntaxNode)() Dim getAccessorDeclaration = If(getMethod.DeclaringSyntaxReferences.Length = 0, Nothing, TryCast(getMethod.DeclaringSyntaxReferences(0).GetSyntax(cancellationToken), AccessorStatementSyntax)) If TypeOf getAccessorDeclaration?.Parent Is AccessorBlockSyntax Then Dim block = DirectCast(getAccessorDeclaration.Parent, AccessorBlockSyntax) statements.AddRange(block.Statements.Select(AddressOf WithFormattingAnnotation)) ElseIf propertyBackingField IsNot Nothing Then Dim fieldReference = GetFieldReference(generator, propertyBackingField) statements.Add(generator.ReturnStatement(fieldReference)) End If getMethod = UpdateExplicitInterfaceImplementations([property], getMethod, desiredGetMethodName) Dim methodDeclaration = generator.MethodDeclaration(getMethod, desiredGetMethodName, statements) methodDeclaration = CopyLeadingTriviaOver(propertyStatement, methodDeclaration, ConvertValueToReturnsRewriter.instance) Return methodDeclaration End Function Private Shared Function WithFormattingAnnotation(statement As StatementSyntax) As StatementSyntax Return statement.WithAdditionalAnnotations(Formatter.Annotation) End Function Private Shared Function GetSetMethod( generator As SyntaxGenerator, [property] As IPropertySymbol, propertyStatement As PropertyStatementSyntax, propertyBackingField As IFieldSymbol, setMethod As IMethodSymbol, desiredSetMethodName As String, cancellationToken As CancellationToken) As SyntaxNode Dim statements = New List(Of SyntaxNode)() Dim setAccessorDeclaration = If(setMethod.DeclaringSyntaxReferences.Length = 0, Nothing, TryCast(setMethod.DeclaringSyntaxReferences(0).GetSyntax(cancellationToken), AccessorStatementSyntax)) If TypeOf setAccessorDeclaration?.Parent Is AccessorBlockSyntax Then Dim block = DirectCast(setAccessorDeclaration.Parent, AccessorBlockSyntax) statements.AddRange(block.Statements.Select(AddressOf WithFormattingAnnotation)) ElseIf propertyBackingField IsNot Nothing Then Dim fieldReference = GetFieldReference(generator, propertyBackingField) statements.Add(generator.AssignmentStatement( fieldReference, generator.IdentifierName(setMethod.Parameters(0).Name))) End If setMethod = UpdateExplicitInterfaceImplementations([property], setMethod, desiredSetMethodName) Dim methodDeclaration = generator.MethodDeclaration(setMethod, desiredSetMethodName, statements) methodDeclaration = CopyLeadingTriviaOver(propertyStatement, methodDeclaration, ConvertValueToParamRewriter.instance) Return methodDeclaration End Function Private Shared Function UpdateExplicitInterfaceImplementations( [property] As IPropertySymbol, method As IMethodSymbol, desiredName As String) As IMethodSymbol ' We have a property like: ' Public ReadOnly Goo As Integer Implements I.Goo' ' ' That property has an implicit getter: ' Public Function get_Goo As Integer Implements I.get_Goo' ' ' We want to generate the new explicit function: ' Public Function GetGoo() As Integer Implements I.GetGoo ' ' To do this we make the new method using the information from the implicit getter ' Function. However, we need to update the 'explicit interface implementations' ' of the implicit getter function so that they point to the updated interface method ' and not the old implicit interface method. Dim updatedImplementations = method.ExplicitInterfaceImplementations.SelectAsArray( Function(i) UpdateExplicitInterfaceImplementation([property], i, desiredName)) Return If(updatedImplementations.SequenceEqual(method.ExplicitInterfaceImplementations), method, CodeGenerationSymbolFactory.CreateMethodSymbol( method, explicitInterfaceImplementations:=updatedImplementations)) End Function Private Shared Function UpdateExplicitInterfaceImplementation( [property] As IPropertySymbol, explicitInterfaceImplMethod As IMethodSymbol, desiredName As String) As IMethodSymbol If explicitInterfaceImplMethod IsNot Nothing Then If explicitInterfaceImplMethod.Name = "get_" + [property].Name OrElse explicitInterfaceImplMethod.Name = "set_" + [property].Name Then Return CodeGenerationSymbolFactory.CreateMethodSymbol( explicitInterfaceImplMethod, name:=desiredName, containingType:=explicitInterfaceImplMethod.ContainingType) End If End If Return explicitInterfaceImplMethod End Function Private Shared Function CopyLeadingTriviaOver(propertyStatement As PropertyStatementSyntax, methodDeclaration As SyntaxNode, documentationCommentRewriter As VisualBasicSyntaxRewriter) As SyntaxNode Return methodDeclaration.WithLeadingTrivia( propertyStatement.GetLeadingTrivia().Select(Function(trivia) ConvertTrivia(trivia, documentationCommentRewriter))) End Function Private Shared Function ConvertTrivia(trivia As SyntaxTrivia, documentationCommentRewriter As VisualBasicSyntaxRewriter) As SyntaxTrivia If trivia.Kind() = SyntaxKind.DocumentationCommentTrivia Then Dim converted = documentationCommentRewriter.Visit(trivia.GetStructure()) Return SyntaxFactory.Trivia(DirectCast(converted, StructuredTriviaSyntax)) End If Return trivia End Function ''' <summary> ''' Used by the documentation comment rewriters to identify top-level <c><value></c> nodes. ''' </summary> Private Shared Function IsValueName(node As XmlNodeSyntax) As Boolean Dim name = TryCast(node, XmlNameSyntax) Return name?.Prefix Is Nothing AndAlso name?.LocalName.ValueText = "value" End Function Public Overrides Function GetPropertyNodeToReplace(propertyDeclaration As SyntaxNode) As SyntaxNode ' In VB we'll have the property statement. If that is parented by a ' property block, we'll want to replace that instead. Otherwise we ' just replace the property statement itself Return If(propertyDeclaration.IsParentKind(SyntaxKind.PropertyBlock), propertyDeclaration.Parent, propertyDeclaration) End Function Protected Overrides Function TryGetCrefSyntax(identifierName As IdentifierNameSyntax) As CrefReferenceSyntax Dim simpleNameCref = TryCast(identifierName.Parent, CrefReferenceSyntax) If simpleNameCref IsNot Nothing Then Return simpleNameCref End If Dim qualifiedName = TryCast(identifierName.Parent, QualifiedNameSyntax) If qualifiedName Is Nothing Then Return Nothing End If Return TryCast(qualifiedName.Parent, CrefReferenceSyntax) End Function Protected Overrides Function CreateCrefSyntax(originalCref As CrefReferenceSyntax, identifierToken As SyntaxToken, parameterType As SyntaxNode) As CrefReferenceSyntax Dim signature As CrefSignatureSyntax Dim parameterSyntax = TryCast(parameterType, TypeSyntax) If parameterSyntax IsNot Nothing Then signature = SyntaxFactory.CrefSignature(SyntaxFactory.CrefSignaturePart(modifier:=Nothing, type:=parameterSyntax)) Else signature = SyntaxFactory.CrefSignature() End If Dim typeReference As TypeSyntax = SyntaxFactory.IdentifierName(identifierToken) Dim qualifiedType = TryCast(originalCref.Name, QualifiedNameSyntax) If qualifiedType IsNot Nothing Then typeReference = qualifiedType.ReplaceNode(qualifiedType.GetLastDottedName(), typeReference) End If Return SyntaxFactory.CrefReference(typeReference, signature, asClause:=Nothing) End Function Protected Overrides Function UnwrapCompoundAssignment(compoundAssignment As SyntaxNode, readExpression As ExpressionSyntax) As ExpressionSyntax Throw New InvalidOperationException("Compound assignments don't exist in VB") End Function End Class End Namespace