/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/VisualBasic/Portable/IntroduceVariable/VisualBasicIntroduceVariableService_IntroduceField.vb
256 строк
13 KB
Cyrus Najmabadi
Remove annotatino
02 дек 2024, 06:34
02 дек 2024, 06:34
94dab6c
Код
Авторство
О чём код?
' 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.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable Partial Friend Class VisualBasicIntroduceVariableService Protected Overrides Async Function IntroduceFieldAsync( document As SemanticDocument, expression As ExpressionSyntax, allOccurrences As Boolean, isConstant As Boolean, cancellationToken As CancellationToken) As Task(Of Document) Dim oldTypeDeclaration = expression.GetAncestorOrThis(Of TypeBlockSyntax)() Dim oldType = If(oldTypeDeclaration IsNot Nothing, document.SemanticModel.GetDeclaredSymbol(oldTypeDeclaration.BlockStatement, cancellationToken), Nothing) Dim newNameToken = GenerateUniqueLocalName( document, expression, isConstant, containerOpt:=Nothing, cancellationToken:=cancellationToken) Dim newQualifiedName = SyntaxFactory.SimpleMemberAccessExpression( expression:=SyntaxFactory.ParseName(oldType.ToNameDisplayString()), operatorToken:=SyntaxFactory.Token(SyntaxKind.DotToken), name:=SyntaxFactory.IdentifierName(newNameToken)).WithAdditionalAnnotations(Simplifier.Annotation) If oldType IsNot Nothing Then Return Await IntroduceFieldIntoTypeAsync( document, expression, newQualifiedName, oldTypeDeclaration, oldType, newNameToken, allOccurrences, isConstant, cancellationToken).ConfigureAwait(False) Else Dim oldCompilationUnit = DirectCast(document.Root, CompilationUnitSyntax) Dim newCompilationUnit = Rewrite(document, expression, newQualifiedName, document, oldCompilationUnit, allOccurrences, cancellationToken) Dim newFieldDeclaration = CreateFieldDeclaration( document, oldTypeDeclaration, newNameToken, expression, allOccurrences, isConstant, cancellationToken) Dim insertionIndex = If(isConstant, DetermineConstantInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members), DetermineFieldInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members)) Dim newRoot = newCompilationUnit.WithMembers( newCompilationUnit.Members.Insert(insertionIndex, newFieldDeclaration)) Return document.Document.WithSyntaxRoot(newRoot) End If End Function Private Async Function IntroduceFieldIntoTypeAsync( document As SemanticDocument, expression As ExpressionSyntax, newQualifiedName As MemberAccessExpressionSyntax, oldTypeBlock As TypeBlockSyntax, oldType As INamedTypeSymbol, newNameToken As SyntaxToken, allOccurrences As Boolean, isConstant As Boolean, cancellationToken As CancellationToken) As Task(Of Document) Dim oldToNewTypeBlockMap = New Dictionary(Of TypeBlockSyntax, TypeBlockSyntax) For Each declNode In oldType.DeclaringSyntaxReferences.Select(Function(r) r.GetSyntax().Parent).OfType(Of TypeBlockSyntax)() Dim currentDocument = Await SemanticDocument.CreateAsync(document.Project.Solution.GetDocument(declNode.SyntaxTree), cancellationToken).ConfigureAwait(False) Dim newDeclNode = Rewrite(document, expression, newQualifiedName, currentDocument, declNode, allOccurrences, cancellationToken) oldToNewTypeBlockMap(declNode) = newDeclNode Next Dim newTypeDeclaration = oldToNewTypeBlockMap(oldTypeBlock) Dim insertionIndex = GetFieldInsertionIndex(isConstant, oldTypeBlock, newTypeDeclaration, cancellationToken) Dim destination As SyntaxNode = oldTypeBlock Dim newFieldDeclaration = CreateFieldDeclaration( document, oldTypeBlock, newNameToken, expression, allOccurrences, isConstant, cancellationToken) Dim finalTypeDeclaration = InsertMember(newTypeDeclaration, newFieldDeclaration, insertionIndex) oldToNewTypeBlockMap(oldTypeBlock) = finalTypeDeclaration Dim typeBlocksGroupedByTree = oldToNewTypeBlockMap.GroupBy(Function(kvp) kvp.Key.SyntaxTree) Dim updatedDocument = document.Document For Each group In typeBlocksGroupedByTree Dim syntaxTree = group.Key Dim currentDocument = document.Project.Solution.GetDocument(syntaxTree) Dim oldRoot = syntaxTree.GetRoot(cancellationToken) Dim newRoot = oldRoot.ReplaceNodes( group.Select(Function(kvp) kvp.Key), Function(n1, n2) Return oldToNewTypeBlockMap(n1) End Function) updatedDocument = updatedDocument.Project.Solution.GetDocument(currentDocument.Id).WithSyntaxRoot(newRoot) Next Return updatedDocument End Function Protected Overrides Function DetermineConstantInsertPosition(oldDeclaration As TypeBlockSyntax, newDeclaration As TypeBlockSyntax) As Integer Return DetermineConstantInsertPosition(oldDeclaration.Members, newDeclaration.Members) End Function Protected Overloads Shared Function DetermineConstantInsertPosition(oldMembers As SyntaxList(Of StatementSyntax), newMembers As SyntaxList(Of StatementSyntax)) As Integer ' 1) Place the constant after the last constant. ' ' 2) If there is no constant, place it before the first field ' ' 3) If the first change is before either of those, then place before the first ' change ' ' 4) Otherwise, place it at the start. Dim index = 0 Dim lastConstantIndex = oldMembers.LastIndexOf(AddressOf IsConstantField) If lastConstantIndex >= 0 Then index = lastConstantIndex + 1 Else Dim firstFieldIndex = oldMembers.IndexOf(Function(member) TypeOf member Is FieldDeclarationSyntax) If firstFieldIndex >= 0 Then index = firstFieldIndex End If End If Dim firstChangeIndex = DetermineFirstChange(oldMembers, newMembers) If firstChangeIndex >= 0 Then index = Math.Min(index, firstChangeIndex) End If Return index End Function Protected Overrides Function DetermineFieldInsertPosition(oldDeclaration As TypeBlockSyntax, newDeclaration As TypeBlockSyntax) As Integer Return DetermineFieldInsertPosition(oldDeclaration.Members, newDeclaration.Members) End Function Protected Overloads Shared Function DetermineFieldInsertPosition(oldMembers As SyntaxList(Of StatementSyntax), newMembers As SyntaxList(Of StatementSyntax)) As Integer ' 1) Place the constant after the last field. ' ' 2) If there is no field, place it after the last constant ' ' 3) If the first change is before either of those, then place before the first ' change ' ' 4) Otherwise, place it at the start. Dim index = 0 Dim lastFieldIndex = oldMembers.LastIndexOf(Function(member) TypeOf member Is FieldDeclarationSyntax) If lastFieldIndex >= 0 Then index = lastFieldIndex + 1 Else Dim lastConstantIndex = oldMembers.LastIndexOf(AddressOf IsConstantField) If lastConstantIndex >= 0 Then index = lastConstantIndex + 1 End If End If Dim firstChangeIndex = DetermineFirstChange(oldMembers, newMembers) If firstChangeIndex >= 0 Then index = Math.Min(index, firstChangeIndex) End If Return index End Function Private Shared Function IsConstantField(member As StatementSyntax) As Boolean Dim field = TryCast(member, FieldDeclarationSyntax) Return field IsNot Nothing AndAlso field.Modifiers.Any(SyntaxKind.ConstKeyword) End Function Protected Shared Function DetermineFirstChange(oldMembers As SyntaxList(Of StatementSyntax), newMembers As SyntaxList(Of StatementSyntax)) As Integer Dim i As Integer = 0 While i < oldMembers.Count If Not SyntaxFactory.AreEquivalent(oldMembers(i), newMembers(i), topLevel:=False) Then Return i End If i = i + 1 End While Return -1 End Function Private Function CreateFieldDeclaration( document As SemanticDocument, oldTypeDeclaration As TypeBlockSyntax, newNameToken As SyntaxToken, expression As ExpressionSyntax, allOccurrences As Boolean, isConstant As Boolean, cancellationToken As CancellationToken) As FieldDeclarationSyntax Dim matches = FindMatches(document, expression, document, {oldTypeDeclaration}, allOccurrences, cancellationToken) Dim trimmedExpression = expression.WithoutTrailingTrivia().WithoutLeadingTrivia() Return SyntaxFactory.FieldDeclaration( Nothing, MakeFieldModifiers(matches, isConstant, inScript:=oldTypeDeclaration Is Nothing, inModule:=oldTypeDeclaration.Kind = SyntaxKind.ModuleBlock), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ModifiedIdentifier(newNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()))), asClause:=SyntaxFactory.SimpleAsClause(GetTypeSymbol(document, expression, cancellationToken).GenerateTypeSyntax()), initializer:=SyntaxFactory.EqualsValue(value:=trimmedExpression)))) _ .WithAppendedTrailingTrivia(SyntaxFactory.ElasticMarker) _ .WithAdditionalAnnotations(Formatter.Annotation) End Function Private Shared Function MakeFieldModifiers(expressions As IEnumerable(Of ExpressionSyntax), isConstant As Boolean, inScript As Boolean, inModule As Boolean) As SyntaxTokenList Dim modifiers = New List(Of SyntaxToken) Dim inTypeAttribute = expressions.Select(Function(e) e.GetAncestor(Of AttributeListSyntax)()). WhereNotNull(). Any(Function(a) TypeOf a.Parent Is TypeStatementSyntax) If inTypeAttribute Then modifiers.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)) Else modifiers.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) End If If isConstant Then modifiers.Add(SyntaxFactory.Token(SyntaxKind.ConstKeyword)) ElseIf inScript Then modifiers.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)) ElseIf inModule Then modifiers.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)) Else modifiers.Add(SyntaxFactory.Token(SyntaxKind.SharedKeyword)) modifiers.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)) End If Return SyntaxFactory.TokenList(modifiers) End Function Protected Shared Function InsertMember(typeDeclaration As TypeBlockSyntax, memberDeclaration As StatementSyntax, index As Integer) As TypeBlockSyntax Return typeDeclaration.WithMembers( typeDeclaration.Members.Insert(index, memberDeclaration)) End Function End Class End Namespace