/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/VisualBasic/Portable/ReplaceMethodWithProperty/VisualBasicReplaceMethodWithPropertyService.vb
219 строк
12 KB
Cyrus Najmabadi
usings
07 сен 2023, 23:24
07 сен 2023, 23:24
c3c78e5
Код
Авторство
О чём код?
' 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.CodeActions Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.ReplaceMethodWithProperty Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.ReplaceMethodWithProperty <ExportLanguageService(GetType(IReplaceMethodWithPropertyService), LanguageNames.VisualBasic), [Shared]> Friend Class VisualBasicReplaceMethodWithPropertyService Inherits AbstractReplaceMethodWithPropertyService(Of MethodStatementSyntax) Implements IReplaceMethodWithPropertyService <ImportingConstructor> <Obsolete(MefConstruction.ImportingConstructorMessage, True)> Public Sub New() End Sub Public Sub RemoveSetMethod(editor As SyntaxEditor, setMethodDeclaration As SyntaxNode) Implements IReplaceMethodWithPropertyService.RemoveSetMethod Dim setMethodStatement = TryCast(setMethodDeclaration, MethodStatementSyntax) If setMethodStatement Is Nothing Then Return End If Dim methodOrBlock = GetParentIfBlock(setMethodStatement) editor.RemoveNode(methodOrBlock) End Sub Public Sub ReplaceGetMethodWithProperty( options As CodeGenerationOptions, parseOptions As ParseOptions, editor As SyntaxEditor, semanticModel As SemanticModel, getAndSetMethods As GetAndSetMethods, propertyName As String, nameChanged As Boolean, cancellationToken As CancellationToken) Implements IReplaceMethodWithPropertyService.ReplaceGetMethodWithProperty Dim getMethodDeclaration = TryCast(getAndSetMethods.GetMethodDeclaration, MethodStatementSyntax) If getMethodDeclaration Is Nothing Then Return End If Dim methodBlockOrStatement = GetParentIfBlock(getMethodDeclaration) editor.ReplaceNode(methodBlockOrStatement, ConvertMethodsToProperty(editor, getAndSetMethods, propertyName, nameChanged)) End Sub Private Shared Function GetParentIfBlock(declaration As MethodStatementSyntax) As DeclarationStatementSyntax If declaration.IsParentKind(SyntaxKind.FunctionBlock) OrElse declaration.IsParentKind(SyntaxKind.SubBlock) Then Return DirectCast(declaration.Parent, DeclarationStatementSyntax) End If Return declaration End Function Private Shared Function ConvertMethodsToProperty( editor As SyntaxEditor, getAndSetMethods As GetAndSetMethods, propertyName As String, nameChanged As Boolean) As DeclarationStatementSyntax Dim generator = editor.Generator Dim getMethodStatement = DirectCast(getAndSetMethods.GetMethodDeclaration, MethodStatementSyntax) Dim setMethodStatement = TryCast(getAndSetMethods.SetMethodDeclaration, MethodStatementSyntax) Dim propertyNameToken = GetPropertyName(getMethodStatement.Identifier, propertyName, nameChanged) Dim warning = GetWarning(getAndSetMethods) If warning IsNot Nothing Then propertyNameToken = propertyNameToken.WithAdditionalAnnotations(WarningAnnotation.Create(warning)) End If Dim newPropertyDeclaration As DeclarationStatementSyntax If getAndSetMethods.SetMethod Is Nothing Then Dim modifiers = getMethodStatement.Modifiers.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)) Dim propertyStatement = SyntaxFactory.PropertyStatement( getMethodStatement.AttributeLists, modifiers, propertyNameToken, Nothing, getMethodStatement.AsClause, initializer:=Nothing, implementsClause:=getMethodStatement.ImplementsClause) If getAndSetMethods.GetMethodDeclaration.IsParentKind(SyntaxKind.FunctionBlock) Then ' Get method has no body, and we have no setter. Just make a readonly property block Dim accessor = SyntaxFactory.GetAccessorBlock(SyntaxFactory.GetAccessorStatement(), DirectCast(getAndSetMethods.GetMethodDeclaration.Parent, MethodBlockBaseSyntax).Statements) Dim accessors = SyntaxFactory.SingletonList(accessor) newPropertyDeclaration = SyntaxFactory.PropertyBlock(propertyStatement, accessors) Else ' Get method has no body, and we have no setter. Just make a readonly property statement newPropertyDeclaration = propertyStatement End If Else Dim propertyStatement = SyntaxFactory.PropertyStatement( getMethodStatement.AttributeLists, getMethodStatement.Modifiers, propertyNameToken, Nothing, getMethodStatement.AsClause, initializer:=Nothing, implementsClause:=getMethodStatement.ImplementsClause) If getAndSetMethods.GetMethodDeclaration.IsParentKind(SyntaxKind.FunctionBlock) AndAlso getAndSetMethods.SetMethodDeclaration.IsParentKind(SyntaxKind.SubBlock) Then Dim getAccessor = SyntaxFactory.GetAccessorBlock(SyntaxFactory.GetAccessorStatement(), DirectCast(getAndSetMethods.GetMethodDeclaration.Parent, MethodBlockBaseSyntax).Statements) Dim setAccessorStatement = SyntaxFactory.SetAccessorStatement() setAccessorStatement = setAccessorStatement.WithParameterList(setMethodStatement?.ParameterList) If getAndSetMethods.GetMethod.DeclaredAccessibility <> getAndSetMethods.SetMethod.DeclaredAccessibility Then setAccessorStatement = DirectCast(generator.WithAccessibility(setAccessorStatement, getAndSetMethods.SetMethod.DeclaredAccessibility), AccessorStatementSyntax) End If Dim setAccessor = SyntaxFactory.SetAccessorBlock(setAccessorStatement, DirectCast(getAndSetMethods.SetMethodDeclaration.Parent, MethodBlockBaseSyntax).Statements) Dim accessors = SyntaxFactory.List({getAccessor, setAccessor}) newPropertyDeclaration = SyntaxFactory.PropertyBlock(propertyStatement, accessors) Else ' Methods don't have bodies. Just make a property statement newPropertyDeclaration = propertyStatement End If End If newPropertyDeclaration = SetLeadingTrivia( VisualBasicSyntaxFacts.Instance, getAndSetMethods, newPropertyDeclaration) Return newPropertyDeclaration.WithAdditionalAnnotations(Formatter.Annotation) End Function Private Shared Function GetPropertyName(identifier As SyntaxToken, propertyName As String, nameChanged As Boolean) As SyntaxToken Return If(nameChanged, SyntaxFactory.Identifier(propertyName), identifier) End Function Public Sub ReplaceGetReference(editor As SyntaxEditor, nameToken As SyntaxToken, propertyName As String, nameChanged As Boolean) Implements IReplaceMethodWithPropertyService.ReplaceGetReference If nameToken.Kind() <> SyntaxKind.IdentifierToken Then Return End If Dim nameNode = TryCast(nameToken.Parent, IdentifierNameSyntax) If nameNode Is Nothing Then Return End If Dim newName = If(nameChanged, SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(propertyName).WithTriviaFrom(nameToken)), nameNode) Dim parentExpression = If(nameNode.IsRightSideOfDot(), DirectCast(nameNode.Parent, ExpressionSyntax), nameNode) Dim root = If(parentExpression.IsParentKind(SyntaxKind.InvocationExpression), parentExpression.Parent, parentExpression) editor.ReplaceNode( root, Function(c As SyntaxNode, g As SyntaxGenerator) Dim currentRoot = DirectCast(c, ExpressionSyntax) Dim expression = If(currentRoot.IsKind(SyntaxKind.InvocationExpression), DirectCast(currentRoot, InvocationExpressionSyntax).Expression, currentRoot) Dim rightName = expression.GetRightmostName() Return expression.ReplaceNode(rightName, newName.WithTrailingTrivia(currentRoot.GetTrailingTrivia())) End Function) End Sub Public Sub ReplaceSetReference(editor As SyntaxEditor, nameToken As SyntaxToken, propertyName As String, nameChanged As Boolean) Implements IReplaceMethodWithPropertyService.ReplaceSetReference If nameToken.Kind() <> SyntaxKind.IdentifierToken Then Return End If Dim nameNode = TryCast(nameToken.Parent, IdentifierNameSyntax) If nameNode Is Nothing Then Return End If Dim newName = If(nameChanged, SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(propertyName).WithTriviaFrom(nameToken)), nameNode) Dim parentExpression = If(nameNode.IsRightSideOfDot(), DirectCast(nameNode.Parent, ExpressionSyntax), nameNode) If Not parentExpression.IsParentKind(SyntaxKind.InvocationExpression) OrElse Not parentExpression.Parent.IsParentKind(SyntaxKind.ExpressionStatement) Then ' Wasn't invoked. Change the name, but report a conflict. Dim annotation = ConflictAnnotation.Create(FeaturesResources.Non_invoked_method_cannot_be_replaced_with_property) editor.ReplaceNode(nameNode, Function(n, g) newName.WithIdentifier(newName.Identifier.WithAdditionalAnnotations(annotation))) Return End If editor.ReplaceNode( parentExpression.Parent.Parent, Function(statement, generator) Dim expressionStatement = DirectCast(statement, ExpressionStatementSyntax) Dim invocationExpression = DirectCast(expressionStatement.Expression, InvocationExpressionSyntax) Dim expression = invocationExpression.Expression Dim name = If(expression.Kind() = SyntaxKind.SimpleMemberAccessExpression, DirectCast(expression, MemberAccessExpressionSyntax).Name, If(expression.Kind() = SyntaxKind.IdentifierName, DirectCast(expression, IdentifierNameSyntax), Nothing)) If name Is Nothing Then Return statement End If If invocationExpression.ArgumentList?.Arguments.Count <> 1 Then Return statement End If Dim result As SyntaxNode = SyntaxFactory.SimpleAssignmentStatement( expression.ReplaceNode(name, newName), invocationExpression.ArgumentList.Arguments(0).GetExpression()) Return result End Function) End Sub Private Function IReplaceMethodWithPropertyService_GetMethodDeclarationAsync(context As CodeRefactoringContext) As Task(Of SyntaxNode) Implements IReplaceMethodWithPropertyService.GetMethodDeclarationAsync Return GetMethodDeclarationAsync(context) End Function End Class End Namespace