| File: Differencing\Edit.cs | Web Access |
| Project: src\roslyn\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces) |
// 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. #nullable disable using System; using System.Diagnostics; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Differencing; /// <summary> /// Represents an edit operation on a tree or a sequence of nodes. /// </summary> /// <typeparam name="TNode">Tree node.</typeparam> [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] public readonly struct Edit<TNode> : IEquatable<Edit<TNode>> { private readonly TreeComparer<TNode> _comparer; internal Edit(EditKind kind, TreeComparer<TNode> comparer, TNode oldNode, TNode newNode) { Debug.Assert((oldNode == null || oldNode.Equals(null)) == (kind == EditKind.Insert)); Debug.Assert((newNode == null || newNode.Equals(null)) == (kind == EditKind.Delete)); Debug.Assert(comparer == null || oldNode == null || oldNode.Equals(null) || newNode == null || newNode.Equals(null) || !comparer.TreesEqual(oldNode, newNode)); _comparer = comparer; Kind = kind; OldNode = oldNode; NewNode = newNode; } public EditKind Kind { get; } /// <summary> /// Insert: /// default(TNode). /// /// Delete: /// Deleted node. /// /// Move, Update: /// Node in the old tree/sequence. /// </summary> public TNode OldNode { get; } /// <summary> /// Insert: /// Inserted node. /// /// Delete: /// default(TNode) /// /// Move, Update: /// Node in the new tree/sequence. /// </summary> public TNode NewNode { get; } public override bool Equals(object obj) => obj is Edit<TNode> && Equals((Edit<TNode>)obj); public bool Equals(Edit<TNode> other) { return Kind == other.Kind && (OldNode == null) ? other.OldNode == null : OldNode.Equals(other.OldNode) && (NewNode == null) ? other.NewNode == null : NewNode.Equals(other.NewNode); } public override int GetHashCode() { var hash = (int)Kind; if (OldNode != null) { hash = Hash.Combine(OldNode.GetHashCode(), hash); } if (NewNode != null) { hash = Hash.Combine(NewNode.GetHashCode(), hash); } return hash; } // Has to be 'internal' for now as it's used by EnC test tool internal string GetDebuggerDisplay() { var result = Kind.ToString(); switch (Kind) { case EditKind.Delete: return result + " [" + OldNode.ToString() + "]" + DisplayPosition(OldNode); case EditKind.Insert: return result + " [" + NewNode.ToString() + "]" + DisplayPosition(NewNode); case EditKind.Update: return result + " [" + OldNode.ToString() + "]" + DisplayPosition(OldNode) + " -> [" + NewNode.ToString() + "]" + DisplayPosition(NewNode); case EditKind.Move: case EditKind.Reorder: return result + " [" + OldNode.ToString() + "]" + DisplayPosition(OldNode) + " -> " + DisplayPosition(NewNode); } return result; } private string DisplayPosition(TNode node) => (_comparer != null) ? "@" + _comparer.GetSpan(node).Start : ""; }