using System; using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax; using Microsoft.CodeAnalysis.Syntax.InternalSyntax; namespace Microsoft.CodeAnalysis.CSharp.Syntax; internal static class SyntaxEquivalence { internal static bool AreEquivalent(SyntaxTree? before, SyntaxTree? after, Func? ignoreChildNode, bool topLevel) { if (before == after) { return true; } if (before == null || after == null) { return false; } return AreEquivalent(before.GetRoot(default(CancellationToken)), after.GetRoot(default(CancellationToken)), ignoreChildNode, topLevel); } public static bool AreEquivalent(SyntaxNode? before, SyntaxNode? after, Func? ignoreChildNode, bool topLevel) { if (before == null || after == null) { return before == after; } return AreEquivalentRecursive(before.Green, after.Green, ignoreChildNode, topLevel); } public static bool AreEquivalent(SyntaxTokenList before, SyntaxTokenList after) { return AreEquivalentRecursive(((SyntaxTokenList)(ref before)).Node, ((SyntaxTokenList)(ref after)).Node, null, topLevel: false); } public static bool AreEquivalent(SyntaxToken before, SyntaxToken after) { if (((SyntaxToken)(ref before)).RawKind == ((SyntaxToken)(ref after)).RawKind) { if (((SyntaxToken)(ref before)).Node != null) { return AreTokensEquivalent(((SyntaxToken)(ref before)).Node, ((SyntaxToken)(ref after)).Node, null); } return true; } return false; } private static bool AreTokensEquivalent(GreenNode? before, GreenNode? after, Func? ignoreChildNode) { if (before == null || after == null) { if (before == null) { return after == null; } return false; } if (before.IsMissing != after.IsMissing) { return false; } switch ((SyntaxKind)(ushort)before.RawKind) { case SyntaxKind.IdentifierToken: if (((SyntaxToken)(object)before).ValueText != ((SyntaxToken)(object)after).ValueText) { return false; } break; case SyntaxKind.NumericLiteralToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.StringLiteralToken: case SyntaxKind.InterpolatedStringTextToken: case SyntaxKind.SingleLineRawStringLiteralToken: case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.Utf8StringLiteralToken: case SyntaxKind.Utf8SingleLineRawStringLiteralToken: case SyntaxKind.Utf8MultiLineRawStringLiteralToken: if (((SyntaxToken)(object)before).Text != ((SyntaxToken)(object)after).Text) { return false; } break; } return AreNullableDirectivesEquivalent(before, after, ignoreChildNode); } private static bool AreEquivalentRecursive(GreenNode? before, GreenNode? after, Func? ignoreChildNode, bool topLevel) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (before == after) { return true; } if (before == null || after == null) { return false; } if (before.RawKind != after.RawKind) { return false; } if (before.IsToken) { return AreTokensEquivalent(before, after, ignoreChildNode); } if (topLevel) { SyntaxKind syntaxKind = (SyntaxKind)before.RawKind; if (syntaxKind == SyntaxKind.Block || syntaxKind == SyntaxKind.ArrowExpressionClause) { return AreNullableDirectivesEquivalent(before, after, ignoreChildNode); } if ((ushort)before.RawKind == 8873) { Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.FieldDeclarationSyntax obj = (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.FieldDeclarationSyntax)(object)before; Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.FieldDeclarationSyntax fieldDeclarationSyntax = (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.FieldDeclarationSyntax)(object)after; bool num = obj.Modifiers.Any(8350); bool flag = fieldDeclarationSyntax.Modifiers.Any(8350); if (!num && !flag) { ignoreChildNode = (SyntaxKind childKind) => childKind == SyntaxKind.EqualsValueClause; } } } if (ignoreChildNode != null) { ChildSyntaxList val = before.ChildNodesAndTokens(); Enumerator enumerator = ((ChildSyntaxList)(ref val)).GetEnumerator(); val = after.ChildNodesAndTokens(); Enumerator enumerator2 = ((ChildSyntaxList)(ref val)).GetEnumerator(); GreenNode val2; GreenNode val3; do { val2 = null; val3 = null; while (((Enumerator)(ref enumerator)).MoveNext()) { GreenNode current = ((Enumerator)(ref enumerator)).Current; if (current != null && (current.IsToken || !ignoreChildNode((SyntaxKind)current.RawKind))) { val2 = current; break; } } while (((Enumerator)(ref enumerator2)).MoveNext()) { GreenNode current2 = ((Enumerator)(ref enumerator2)).Current; if (current2 != null && (current2.IsToken || !ignoreChildNode((SyntaxKind)current2.RawKind))) { val3 = current2; break; } } if (val2 == null || val3 == null) { return val2 == val3; } } while (AreEquivalentRecursive(val2, val3, ignoreChildNode, topLevel)); return false; } int slotCount = before.SlotCount; if (slotCount != after.SlotCount) { return false; } for (int num2 = 0; num2 < slotCount; num2++) { GreenNode slot = before.GetSlot(num2); GreenNode slot2 = after.GetSlot(num2); if (!AreEquivalentRecursive(slot, slot2, ignoreChildNode, topLevel)) { return false; } } return true; } private static bool AreNullableDirectivesEquivalent(GreenNode before, GreenNode after, Func? ignoreChildNode) { if (ignoreChildNode != null && ignoreChildNode(SyntaxKind.NullableDirectiveTrivia)) { return true; } using (IEnumerator enumerator = ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.CSharpSyntaxNode)(object)before).GetDirectives().GetEnumerator()) { using IEnumerator enumerator2 = ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.CSharpSyntaxNode)(object)after).GetDirectives().GetEnumerator(); Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DirectiveTriviaSyntax directiveTriviaSyntax; Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DirectiveTriviaSyntax directiveTriviaSyntax2; do { directiveTriviaSyntax = getNextNullableDirective(enumerator); directiveTriviaSyntax2 = getNextNullableDirective(enumerator2); if (directiveTriviaSyntax == null || directiveTriviaSyntax2 == null) { return directiveTriviaSyntax == directiveTriviaSyntax2; } } while (AreEquivalentRecursive((GreenNode?)(object)directiveTriviaSyntax, (GreenNode?)(object)directiveTriviaSyntax2, ignoreChildNode, topLevel: false)); return false; } static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DirectiveTriviaSyntax? getNextNullableDirective(IEnumerator enumerator3) { while (enumerator3.MoveNext()) { Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DirectiveTriviaSyntax current = enumerator3.Current; if (current.Kind == SyntaxKind.NullableDirectiveTrivia) { return current; } } return null; } } }