boolean (@NotNull Change change1, @NotNull Change change2) { if (!Comparing.equal(ChangesUtil.getBeforePath(change1), ChangesUtil.getBeforePath(change2)) || !Comparing.equal(ChangesUtil.getAfterPath(change1), ChangesUtil.getAfterPath(change2))) { // we use file paths for hashCode, so removing this check might violate comparison contract return false; } for (ChangeDiffViewerWrapperProvider provider : ChangeDiffViewerWrapperProvider.EP_NAME.getExtensions()) { ThreeState equals = provider.isEquals(change1, change2); if (equals == ThreeState.NO) return false; } for (ChangeDiffRequestProvider provider : ChangeDiffRequestProvider.EP_NAME.getExtensions()) { ThreeState equals = provider.isEquals(change1, change2); if (equals == ThreeState.YES) return true; if (equals == ThreeState.NO) return false; } if (!Comparing.equal(change1.getClass(), change2.getClass())) return false; if (!Comparing.equal(change1.getFileStatus(), change2.getFileStatus())) return false; if (!isEquals(change1.getBeforeRevision(), change2.getBeforeRevision())) return false; if (!isEquals(change1.getAfterRevision(), change2.getAfterRevision())) return false; if (change1 instanceof ChangeListChange || change2 instanceof ChangeListChange) { assert change1 instanceof ChangeListChange && change2 instanceof ChangeListChange; String changelistId1 = ((ChangeListChange)change1).getChangeListId(); String changelistId2 = ((ChangeListChange)change2).getChangeListId(); if (!Objects.equals(changelistId1, changelistId2)) return false; } return true; }