Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java252
1 files changed, 241 insertions, 11 deletions
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
index c4443e9c3..cf7aa9e10 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
@@ -16,6 +16,7 @@ import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEGet;
import com.google.common.base.Optional;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -257,11 +258,102 @@ public class DefaultDiffEngine implements IDiffEngine {
}
/**
+ * Delegates the computation of Differences for a given containment reference according to the type of
+ * comparison (two- or three-way), and whether we need to take ordering changes into account.
+ *
+ * @param match
+ * The match which sides we need to check for potential differences.
+ * @param reference
+ * The reference whose values are currently being checked for differences.
+ * @param checkOrdering
+ * Whether we need to detect ordering changes or ignore them.
+ */
+ protected void computeContainmentDifferences(Match match, EReference reference, boolean checkOrdering) {
+ Comparison comparison = match.getComparison();
+
+ if (checkOrdering) {
+ if (comparison.isThreeWay()) {
+ computeContainmentDifferencesThreeWay(match, reference, checkOrdering);
+ } else {
+ computeContainmentDifferencesTwoWay(match, reference, checkOrdering);
+ }
+ } else {
+ List<Object> leftValues = getAsList(match.getLeft(), reference);
+ List<Object> rightValues = getAsList(match.getRight(), reference);
+ if (comparison.isThreeWay()) {
+ createContainmentDifferencesNoOrdering(match, reference, leftValues, DifferenceSource.LEFT);
+ createContainmentDifferencesNoOrdering(match, reference, rightValues, DifferenceSource.RIGHT);
+
+ List<Object> originValues = getAsList(match.getOrigin(), reference);
+ for (Object value : originValues) {
+ Match valueMatch = comparison.getMatch((EObject)value);
+ if (valueMatch.getLeft() == null) {
+ featureChange(match, reference, value, DifferenceKind.DELETE, DifferenceSource.LEFT);
+ }
+ if (valueMatch.getRight() == null) {
+ featureChange(match, reference, value, DifferenceKind.DELETE, DifferenceSource.RIGHT);
+ }
+ }
+ } else {
+ createContainmentDifferencesNoOrdering(match, reference, leftValues, DifferenceSource.LEFT);
+
+ for (Object value : rightValues) {
+ Match valueMatch = comparison.getMatch((EObject)value);
+ if (valueMatch.getLeft() == null) {
+ featureChange(match, reference, value, DifferenceKind.DELETE, DifferenceSource.LEFT);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Delegates the computation of Differences for a given muti-valued feature according to the type of
+ * comparison (two- or three-way), and whether we need to take ordering changes into account.
+ *
+ * @param match
+ * The match which sides we need to check for potential differences.
+ * @param feature
+ * The feature whose values are currently being checked for differences.
+ * @param checkOrdering
+ * Whether we need to detect ordering changes or ignore them.
+ */
+ protected void computeMultiValuedFeatureDifferences(Match match, EStructuralFeature feature,
+ boolean checkOrdering) {
+ Comparison comparison = match.getComparison();
+
+ if (checkOrdering) {
+ if (comparison.isThreeWay()) {
+ computeMultiValuedFeatureDifferencesThreeWay(match, feature, checkOrdering);
+ } else {
+ computeMultiValuedFeatureDifferencesTwoWay(match, feature, checkOrdering);
+ }
+ } else {
+ List<Object> leftValues = getAsList(match.getLeft(), feature);
+ List<Object> rightValues = getAsList(match.getRight(), feature);
+ if (comparison.isThreeWay()) {
+ List<Object> originValues = getAsList(match.getOrigin(), feature);
+ createMultiValuedFeatureDifferencesNoOrdering(match, feature, leftValues, originValues,
+ DifferenceSource.LEFT);
+ createMultiValuedFeatureDifferencesNoOrdering(match, feature, rightValues, originValues,
+ DifferenceSource.RIGHT);
+ } else {
+ createMultiValuedFeatureDifferencesNoOrdering(match, feature, leftValues, rightValues,
+ DifferenceSource.LEFT);
+ }
+ }
+ }
+
+ /**
* Computes the difference between the sides of the given {@code match} for the given containment
* {@code reference}.
* <p>
* This is only meant for three-way comparisons.
* </p>
+ * <p>
+ * <b>Note</b> that this is no longer used for references which ordering is not considered, so
+ * {@code checkOrdering} will always be <code>true</code> .
+ * </p>
*
* @param match
* The match which sides we need to check for potential differences.
@@ -314,6 +406,59 @@ public class DefaultDiffEngine implements IDiffEngine {
}
/**
+ * This will iterate over the given list of values from a containment reference and create the differences
+ * that can be detected from it.
+ * <p>
+ * Ordering changes will not be considered at all from this method. Values that exist in both the given
+ * list of elements and the origin (either ancestor or right side for two-way comparisons), will only have
+ * a Diff if their container or containing reference has changed. If they are still in the same container
+ * and reference, then even if they are not in the same position, we will not try and detect an ordering
+ * change.
+ * </p>
+ *
+ * @param match
+ * The match which sides we need to check for potential differences.
+ * @param reference
+ * The containment reference which values are to be checked.
+ * @param sideValues
+ * Value of that <code>reference</code> on the given <code>side</code>.
+ * @param side
+ * The side currently being compared.
+ */
+ protected void createContainmentDifferencesNoOrdering(Match match, EReference reference,
+ List<Object> sideValues, DifferenceSource side) {
+ Comparison comparison = match.getComparison();
+ IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+
+ int sizeSide = sideValues.size();
+
+ int currentSide = 0;
+ while (currentSide < sizeSide) {
+ EObject sideValue = (EObject)sideValues.get(currentSide++);
+ Match candidateMatch = comparison.getMatch(sideValue);
+
+ EObject originValue;
+ if (comparison.isThreeWay()) {
+ originValue = candidateMatch.getOrigin();
+ } else {
+ originValue = candidateMatch.getRight();
+ }
+
+ if (matchingContainment(equalityHelper, sideValue, originValue)) {
+ // Object present in both sides, in the same container and same containment feature.
+ // We don't care about ordering so there is no change here.
+ } else {
+ // Object has either changed container or isn't present in the origin
+ if (originValue != null) {
+ featureChange(match, reference, sideValue, DifferenceKind.MOVE, side);
+ } else {
+ featureChange(match, reference, sideValue, DifferenceKind.ADD, side);
+ }
+ }
+ }
+ }
+
+ /**
* Called from {@link #computeContainmentDifferencesThreeWay(Match, EReference, boolean)} once our LCS
* have been computed and we know what really changed. It will be used for both the left and right side.
*
@@ -464,6 +609,10 @@ public class DefaultDiffEngine implements IDiffEngine {
* <p>
* This is only meant for two-way comparisons.
* </p>
+ * <p>
+ * <b>Note</b> that this is no longer used for references which ordering is not considered, so
+ * {@code checkOrdering} will always be <code>true</code> .
+ * </p>
*
* @param match
* The match which sides we need to check for potential differences.
@@ -522,7 +671,7 @@ public class DefaultDiffEngine implements IDiffEngine {
shortcut = match.getLeft() == null || match.getRight() == null;
}
- // Do not shortcut when manyvalued FeatureMaps are affected to keep their ordering intact
+ // Do not shortcut when multi-valued FeatureMaps are affected to keep their ordering intact
if (shortcut && FeatureMapUtil.isFeatureMap(attribute)) {
final EObject owner = getOwner(match);
if (owner != null && FeatureMapUtil.isMany(owner, attribute)) {
@@ -579,17 +728,9 @@ public class DefaultDiffEngine implements IDiffEngine {
final Comparison comparison = match.getComparison();
if (reference.isContainment()) {
- if (comparison.isThreeWay()) {
- computeContainmentDifferencesThreeWay(match, reference, checkOrdering);
- } else {
- computeContainmentDifferencesTwoWay(match, reference, checkOrdering);
- }
+ computeContainmentDifferences(match, reference, checkOrdering);
} else if (reference.isMany()) {
- if (comparison.isThreeWay()) {
- computeMultiValuedFeatureDifferencesThreeWay(match, reference, checkOrdering);
- } else {
- computeMultiValuedFeatureDifferencesTwoWay(match, reference, checkOrdering);
- }
+ computeMultiValuedFeatureDifferences(match, reference, checkOrdering);
} else {
if (comparison.isThreeWay()) {
computeSingleValuedReferenceDifferencesThreeWay(match, reference);
@@ -608,6 +749,10 @@ public class DefaultDiffEngine implements IDiffEngine {
* <p>
* This is only meant for three-way comparisons.
* </p>
+ * <p>
+ * <b>Note</b> that this is no longer used for features which ordering is not considered, so
+ * {@code checkOrdering} will always be <code>true</code> .
+ * </p>
*
* @param match
* The match which sides we need to check for potential differences.
@@ -718,6 +863,87 @@ public class DefaultDiffEngine implements IDiffEngine {
}
/**
+ * This will iterate over the given list of values from a multi-valued feature and create the differences
+ * that can be detected from it.
+ * <p>
+ * Ordering changes will not be considered at all from this method. Values that exist in both the given
+ * list of elements and the origin (either ancestor or right side for two-way comparisons), will never
+ * have a Diff even if they are not at the same index in the list of their respective side.
+ * </p>
+ *
+ * @param match
+ * The match which sides we need to check for potential differences.
+ * @param feature
+ * The feature which values are to be checked. Cannot be a containment reference.
+ * @param sideValues
+ * Value of that <code>reference</code> on the given <code>side</code>.
+ * @param originValues
+ * Value of that <code>reference</code> on the origin side. Could be the common ancestor or the
+ * right side in case of two-way comparisons.
+ * @param side
+ * The side currently being compared.
+ */
+ protected void createMultiValuedFeatureDifferencesNoOrdering(Match match, EStructuralFeature feature,
+ List<Object> sideValues, List<Object> originValues, DifferenceSource side) {
+ Comparison comparison = match.getComparison();
+ IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+
+ List<Object> originCopy = new ArrayList<>(originValues);
+
+ int sizeSide = sideValues.size();
+ int currentSide = 0;
+ while (currentSide < sizeSide) {
+ Object sideValue = sideValues.get(currentSide++);
+
+ int currentOrigin = 0;
+ int sizeOrigin = originCopy.size();
+
+ boolean matching = false;
+ while (currentOrigin < sizeOrigin && !matching) {
+ Object originValue = originCopy.get(currentOrigin);
+ if (equalityHelper.matchingValues(sideValue, originValue)) {
+ originCopy.remove(currentOrigin);
+ matching = true;
+ }
+ currentOrigin++;
+ }
+
+ if (!matching) {
+ // This object is in the side checked, but not in the origin
+ if (FeatureMapUtil.isFeatureMap(feature) && sideValue instanceof FeatureMap.Entry) {
+ // A value of a FeatureMap changed its key
+ if (isFeatureMapEntryKeyChange(equalityHelper, (FeatureMap.Entry)sideValue,
+ originValues)) {
+ featureChange(match, feature, sideValue, DifferenceKind.CHANGE, side);
+ } else if (isFeatureMapValueMove(comparison, (FeatureMap.Entry)sideValue, side)) {
+ featureChange(match, feature, sideValue, DifferenceKind.MOVE, side);
+ } else {
+ featureChange(match, feature, sideValue, DifferenceKind.ADD, side);
+ }
+ } else {
+ featureChange(match, feature, sideValue, DifferenceKind.ADD, side);
+ }
+ }
+ }
+
+ // Objects that are still present in "originCopy" now have been deleted from the current side.
+ // We want all reference changes, but if the current side has been deleted, we do not want to have
+ // attribute changes under this deletion.
+ boolean sideDeleted;
+ if (side == DifferenceSource.LEFT) {
+ sideDeleted = match.getLeft() == null;
+ } else {
+ sideDeleted = match.getRight() == null;
+ }
+ for (Object originValue : originCopy) {
+ if ((feature instanceof EReference || !sideDeleted)
+ && !isFeatureMapChangeOrMove(comparison, feature, originValue, sideValues, side)) {
+ featureChange(match, feature, originValue, DifferenceKind.DELETE, side);
+ }
+ }
+ }
+
+ /**
* Computes the difference between the sides of the given {@code match} for the given multi-valued
* {@code feature}.
* <p>
@@ -726,6 +952,10 @@ public class DefaultDiffEngine implements IDiffEngine {
* <p>
* This is only meant for two-way comparisons.
* </p>
+ * <p>
+ * <b>Note</b> that this is no longer used for features which ordering is not considered, so
+ * {@code checkOrdering} will always be <code>true</code> .
+ * </p>
*
* @param match
* The match which sides we need to check for potential differences.

Back to the top