@@ -924,6 +924,42 @@ private static <L extends Label> boolean isSameAs(DiffNode<L> a, DiffNode<L> b,
924924 return aIt .hasNext () == bIt .hasNext ();
925925 }
926926
927+ /**
928+ * Returns true if this subtree is exactly equal to {@code other} except for line numbers and other metadata in labels.
929+ * This equality is a weaker equality than {@link DiffNode#isSameAs(DiffNode)} (i.e., whenever isSameAs returns true, so does
930+ * isSameAsIgnoringLineNumbers).
931+ * Labels of DiffNodes are compared via {@link Label#observablyEqual(Label, Label)}.
932+ * This check uses equality checks instead of identity.
933+ */
934+ public boolean isSameAsIgnoringLineNumbers (DiffNode <L > other ) {
935+ return isSameAsIgnoringLineNumbers (this , other , new HashSet <>());
936+ }
937+
938+ private static <L extends Label > boolean isSameAsIgnoringLineNumbers (DiffNode <L > a , DiffNode <L > b , Set <DiffNode <L >> visited ) {
939+ if (!visited .add (a )) {
940+ return true ;
941+ }
942+
943+ if (!(
944+ a .getDiffType ().equals (b .getDiffType ()) &&
945+ a .getNodeType ().equals (b .getNodeType ()) &&
946+ Objects .equals (a .getFormula (), b .getFormula ()) &&
947+ Label .observablyEqual (a .getLabel (), b .getLabel ())
948+ )) {
949+ return false ;
950+ }
951+
952+ Iterator <DiffNode <L >> aIt = a .getAllChildren ().iterator ();
953+ Iterator <DiffNode <L >> bIt = b .getAllChildren ().iterator ();
954+ while (aIt .hasNext () && bIt .hasNext ()) {
955+ if (!isSameAsIgnoringLineNumbers (aIt .next (), bIt .next (), visited )) {
956+ return false ;
957+ }
958+ }
959+
960+ return aIt .hasNext () == bIt .hasNext ();
961+ }
962+
927963 @ Override
928964 public String toString () {
929965 String s ;
0 commit comments