/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Syntax/SyntaxEquivalence.vb
208 строк
9 KB
Tomáš Matoušek
Fixes comparison of VB XML literals (#75301)
02 окт 2024, 07:19
Не верифицирован
02 окт 2024, 07:19
1cd3100
Код
Авторство
О чём код?
' 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 Green = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax Friend Module SyntaxEquivalence Friend Function AreEquivalent(before As SyntaxTree, after As SyntaxTree, ignoreChildNode As Func(Of SyntaxKind, Boolean), topLevel As Boolean) As Boolean If before Is after Then Return True End If If before Is Nothing OrElse after Is Nothing Then Return False End If Return AreEquivalent(before.GetRoot(), after.GetRoot(), ignoreChildNode, topLevel) End Function Public Function AreEquivalent(before As SyntaxNode, after As SyntaxNode, ignoreChildNode As Func(Of SyntaxKind, Boolean), topLevel As Boolean) As Boolean Debug.Assert(Not topLevel OrElse ignoreChildNode Is Nothing) If before Is Nothing OrElse after Is Nothing Then Return before Is after End If Return AreEquivalentRecursive(before.Green, after.Green, parentKind:=Nothing, ignoreChildNode:=ignoreChildNode, topLevel:=topLevel) End Function Public Function AreEquivalent(before As SyntaxTokenList, after As SyntaxTokenList) As Boolean Return AreEquivalentRecursive(before.Node, after.Node, parentKind:=Nothing, ignoreChildNode:=Nothing, topLevel:=False) End Function Public Function AreEquivalent(before As SyntaxToken, after As SyntaxToken) As Boolean Return before.RawKind = after.RawKind AndAlso (before.Node Is Nothing OrElse AreTokensEquivalent(before.Node, after.Node)) End Function Private Function AreTokensEquivalent(before As GreenNode, after As GreenNode) As Boolean Debug.Assert(before.RawKind = after.RawKind) If before.IsMissing <> after.IsMissing Then Return False End If Select Case CType(before.RawKind, SyntaxKind) Case SyntaxKind.IdentifierToken, SyntaxKind.CharacterLiteralToken, SyntaxKind.DateLiteralToken, SyntaxKind.DecimalLiteralToken, SyntaxKind.FloatingLiteralToken, SyntaxKind.IntegerLiteralToken, SyntaxKind.InterpolatedStringTextToken, SyntaxKind.StringLiteralToken, SyntaxKind.XmlTextLiteralToken, SyntaxKind.XmlNameToken Return String.Equals(DirectCast(before, Green.SyntaxToken).Text, DirectCast(after, Green.SyntaxToken).Text, StringComparison.Ordinal) End Select Return True End Function Private Function AreEquivalentRecursive(before As GreenNode, after As GreenNode, parentKind As SyntaxKind, ignoreChildNode As Func(Of SyntaxKind, Boolean), topLevel As Boolean) As Boolean If before Is after Then Return True End If If before Is Nothing OrElse after Is Nothing Then Return False End If If before.RawKind <> after.RawKind Then Return False End If If before.IsToken Then Debug.Assert(after.IsToken) Return AreTokensEquivalent(before, after) End If Dim kind = CType(before.RawKind, SyntaxKind) If Not AreModifiersEquivalent(before, after, kind) Then Return False End If If topLevel Then Select Case kind Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock, SyntaxKind.ConstructorBlock, SyntaxKind.OperatorBlock, SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock, SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock ' Once we get down to the block level we need to only compare the header Return AreEquivalentRecursive(DirectCast(before, Green.MethodBlockBaseSyntax).Begin, DirectCast(after, Green.MethodBlockBaseSyntax).Begin, kind, ignoreChildNode:=Nothing, topLevel:=True) Case SyntaxKind.FieldDeclaration ' If we're only checking top level equivalence, then we don't have to go down into ' the initializer for a field. However, we can't put that optimization for all ' fields. For example, fields that are 'const' do need their initializers checked as ' changing them can affect binding results. Dim fieldBefore = DirectCast(before, Green.FieldDeclarationSyntax) Dim fieldAfter = DirectCast(after, Green.FieldDeclarationSyntax) Dim isConstBefore = fieldBefore.Modifiers.Any(SyntaxKind.ConstKeyword) Dim isConstAfter = fieldAfter.Modifiers.Any(SyntaxKind.ConstKeyword) If Not isConstBefore AndAlso Not isConstAfter Then ignoreChildNode = Function(childKind) childKind = SyntaxKind.EqualsValue OrElse childKind = SyntaxKind.AsNewClause End If Case SyntaxKind.EqualsValue ' Don't recurse into an auto-property initializer. If parentKind = SyntaxKind.PropertyStatement Then Return True End If End Select End If If ignoreChildNode IsNot Nothing Then Dim e1 = DirectCast(before, Green.VisualBasicSyntaxNode).ChildNodesAndTokens().GetEnumerator() Dim e2 = DirectCast(after, Green.VisualBasicSyntaxNode).ChildNodesAndTokens().GetEnumerator() While True Dim child1 As GreenNode = Nothing Dim child2 As GreenNode = Nothing ' skip ignored children While e1.MoveNext() Dim c = e1.Current If c IsNot Nothing AndAlso (c.IsToken OrElse Not ignoreChildNode(CType(c.RawKind, SyntaxKind))) Then child1 = c Exit While End If End While While e2.MoveNext() Dim c = e2.Current If c IsNot Nothing AndAlso (c.IsToken OrElse Not ignoreChildNode(CType(c.RawKind, SyntaxKind))) Then child2 = c Exit While End If End While If child1 Is Nothing OrElse child2 Is Nothing Then ' false if some children remained Return child1 Is child2 End If If Not AreEquivalentRecursive(child1, child2, kind, ignoreChildNode, topLevel) Then Return False End If End While Throw ExceptionUtilities.Unreachable Else ' simple comparison - not ignoring children Dim slotCount1 = before.SlotCount If slotCount1 <> after.SlotCount Then Return False End If For i = 0 To slotCount1 - 1 Dim child1 = before.GetSlot(i) Dim child2 = after.GetSlot(i) If Not AreEquivalentRecursive(child1, child2, kind, ignoreChildNode, topLevel) Then Return False End If Next Return True End If End Function Private Function AreModifiersEquivalent(before As GreenNode, after As GreenNode, kind As SyntaxKind) As Boolean Select Case kind Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock Dim beforeModifiers = DirectCast(before, Green.MethodBlockBaseSyntax).Begin.Modifiers Dim afterModifiers = DirectCast(after, Green.MethodBlockBaseSyntax).Begin.Modifiers If beforeModifiers.Count <> afterModifiers.Count Then Return False End If For i = 0 To beforeModifiers.Count - 1 If Not beforeModifiers.Any(afterModifiers(i).Kind) Then Return False End If Next End Select Return True End Function End Module End Namespace