Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java15
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java16
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java125
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java112
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java26
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java127
10 files changed, 184 insertions, 241 deletions
diff --git a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java
index c56a38df6..9e649ea2b 100644
--- a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java
+++ b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java
@@ -10,11 +10,14 @@
*******************************************************************************/
package org.eclipse.emf.compare.diagram.papyrus.tests.merge;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.all;
import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
import static org.eclipse.emf.compare.ConflictKind.REAL;
import static org.eclipse.emf.compare.DifferenceKind.MOVE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.isInRealAddAddConflict;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -37,7 +40,6 @@ import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.lib.Repository;
import org.junit.runner.RunWith;
-import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
@RunWith(GitTestRunner.class)
@@ -56,7 +58,8 @@ public class AdditiveMergeDiagramTests {
Comparison comparison = support.compare("wave", "expected", "model.notation");
- assertTrue(all(comparison.getDifferences(), hasDirectOrIndirectConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "wired", remote = "wave")
@@ -68,7 +71,8 @@ public class AdditiveMergeDiagramTests {
Comparison comparison = support.compare("wired", "expected", "model.notation");
- assertTrue(all(comparison.getDifferences(), hasDirectOrIndirectConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
/**
@@ -90,7 +94,7 @@ public class AdditiveMergeDiagramTests {
// Let's just check that all diffs are in conflict
Collection<Diff> diffs = Collections2.filter(comparison.getDifferences(),
- Predicates.not(hasDirectOrIndirectConflict(PSEUDO, REAL)));
+ not(hasDirectOrIndirectConflict(PSEUDO, REAL)));
assertEquals(2, diffs.size());
// Since we cannot be sure of the order of the merged element, this is possible that a side and the
@@ -116,6 +120,7 @@ public class AdditiveMergeDiagramTests {
// package on both sides and it's (currently) impossible to guarantee
// the order in which they will be placed in their parent during a merge
// Let's just check that all diffs are in conflict
- assertTrue(all(comparison.getDifferences(), hasDirectOrIndirectConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java
index a5114bdef..28d1147b9 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java
@@ -8,8 +8,11 @@
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.tests.merge;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.all;
import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.isInRealAddAddConflict;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -24,7 +27,6 @@ import org.eclipse.emf.compare.ide.ui.tests.git.framework.GitTestSupport;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.annotations.GitInput;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.annotations.GitMerge;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.annotations.GitMergeStrategy;
-import org.eclipse.emf.compare.utils.EMFComparePredicates;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.lib.Repository;
import org.junit.runner.RunWith;
@@ -43,7 +45,8 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch1", "expected", "network.ecore");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "branch2", remote = "branch1")
@@ -55,7 +58,8 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch2", "expected", "network.ecore");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "branch1", remote = "branch2")
@@ -67,7 +71,8 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch1", "expected", "network.uml");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "branch2", remote = "branch1")
@@ -79,6 +84,7 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch2", "expected", "network.uml");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
index 98ad60f4a..38c2b6293 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
@@ -12,14 +12,11 @@
*******************************************************************************/
package org.eclipse.emf.compare.conflict;
-import static com.google.common.base.Predicates.and;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isAddOrSetDiff;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isDeleteOrUnsetDiff;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isFeatureMapContainment;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueIs;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -280,7 +277,7 @@ public class DefaultConflictDetector implements IConflictDetector {
} else if (diff.getMatch() == candidate.getMatch()
&& diff.getReference() == candidate.getReference()) {
// Same value added in the same container/reference couple
- if (!diffIsDelete && !candidateIsDelete && matchingIndices(comparison, diff.getMatch(),
+ if (!diffIsDelete && !candidateIsDelete && matchingIndices(diff.getMatch(),
diff.getReference(), diff.getValue(), candidate.getValue())) {
kind = ConflictKind.PSEUDO;
}
@@ -381,9 +378,8 @@ public class DefaultConflictDetector implements IConflictDetector {
} else if (diff.getMatch() == candidate.getMatch()
&& diff.getAttribute() == candidate.getAttribute()) {
// Same value added in the same container/reference couple with the same key
- if (!diffIsDelete
- && !candidateIsDelete && matchingIndices(comparison, diff.getMatch(),
- diff.getAttribute(), diff.getValue(), candidate.getValue())
+ if (!diffIsDelete && !candidateIsDelete && matchingIndices(diff.getMatch(),
+ diff.getAttribute(), diff.getValue(), candidate.getValue())
&& haveSameKey(diff, candidate)) {
kind = ConflictKind.PSEUDO;
}
@@ -673,7 +669,7 @@ public class DefaultConflictDetector implements IConflictDetector {
if (diff.getMatch() == candidate.getMatch()
&& comparison.getEqualityHelper().matchingValues(changedValue, candidateValue)) {
// Same value moved in both side of the same container
- if (matchingIndices(comparison, diff.getMatch(), feature, changedValue, candidateValue)) {
+ if (matchingIndices(diff.getMatch(), feature, changedValue, candidateValue)) {
conflictOn(comparison, diff, candidate, ConflictKind.PSEUDO);
} else {
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
@@ -839,8 +835,7 @@ public class DefaultConflictDetector implements IConflictDetector {
// same value can appear twice.
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
}
- } else if (matchingIndices(comparison, diff.getMatch(), feature, addedValue,
- candidateValue)) {
+ } else if (matchingIndices(diff.getMatch(), feature, addedValue, candidateValue)) {
conflictOn(comparison, diff, candidate, ConflictKind.PSEUDO);
} else {
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
@@ -1044,114 +1039,6 @@ public class DefaultConflictDetector implements IConflictDetector {
}
/**
- * This will be used whenever we check for conflictual MOVEs in order to determine whether we have a
- * pseudo conflict or a real conflict.
- * <p>
- * Namely, this will retrieve the value of the given {@code feature} on the right and left sides of the
- * given {@code match}, then check whether the two given values are on the same index.
- * </p>
- * <p>
- * Note that no sanity checks will be made on either the match's sides or the feature.
- * </p>
- *
- * @param comparison
- * Provides us with the necessary information to match EObjects.
- * @param match
- * Match for which we need to check a feature.
- * @param feature
- * The feature which values we need to check.
- * @param value1
- * First of the two values which index we are to compare.
- * @param value2
- * Second of the two values which index we are to compare.
- * @return {@code true} if the two given values are located at the same index in the given feature's
- * values list, {@code false} otherwise.
- */
- @SuppressWarnings("unchecked")
- private boolean matchingIndices(Comparison comparison, Match match, EStructuralFeature feature,
- Object value1, Object value2) {
- boolean matching = false;
- if (feature.isMany()) {
- final List<Object> leftValues = (List<Object>)ReferenceUtil.safeEGet(match.getLeft(), feature);
- final List<Object> rightValues = (List<Object>)ReferenceUtil.safeEGet(match.getRight(), feature);
-
- // FIXME the detection _will_ fail for non-unique lists with multiple identical values...
- int leftIndex = -1;
- int rightIndex = -1;
- for (int i = 0; i < leftValues.size(); i++) {
- final Object left = leftValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(left, value1)) {
- break;
- } else if (hasDiff(match, feature, left) || hasDeleteDiff(match, feature, left)) {
- // Do not increment.
- } else {
- leftIndex++;
- }
- }
- for (int i = 0; i < rightValues.size(); i++) {
- final Object right = rightValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(right, value2)) {
- break;
- } else if (hasDiff(match, feature, right) || hasDeleteDiff(match, feature, right)) {
- // Do not increment.
- } else {
- rightIndex++;
- }
- }
- matching = leftIndex == rightIndex;
- } else {
- matching = true;
- }
- return matching;
- }
-
- /**
- * Checks whether the given {@code match} presents a difference of any kind on the given {@code feature}'s
- * {@code value}.
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have changed inside {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- private boolean hasDiff(Match match, EStructuralFeature feature, Object value) {
- return Iterables.any(match.getDifferences(), and(onFeature(feature.getName()), valueIs(value)));
- }
-
- /**
- * Checks whether the given {@code value} has been deleted from the given {@code feature} of {@code match}
- * .
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have been removed from {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- @SuppressWarnings("unchecked")
- private boolean hasDeleteDiff(Match match, EStructuralFeature feature, Object value) {
- final Comparison comparison = match.getComparison();
- final Object expectedValue;
- if (value instanceof EObject && comparison.isThreeWay()) {
- final Match valueMatch = comparison.getMatch((EObject)value);
- if (valueMatch != null) {
- expectedValue = valueMatch.getOrigin();
- } else {
- expectedValue = value;
- }
- } else {
- expectedValue = value;
- }
- return Iterables.any(match.getDifferences(),
- and(onFeature(feature.getName()), valueIs(expectedValue), ofKind(DifferenceKind.DELETE)));
- }
-
- /**
* This will be called whenever we detect a new conflict in order to create (or update) the actual
* association.
*
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java
index 9eda013a4..4adecb1b2 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java
@@ -13,16 +13,10 @@ package org.eclipse.emf.compare.internal.conflict;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Predicates.and;
import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
import static org.eclipse.emf.compare.ConflictKind.REAL;
-import static org.eclipse.emf.compare.DifferenceKind.DELETE;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueIs;
import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.List;
@@ -47,7 +41,6 @@ import org.eclipse.emf.compare.internal.ThreeWayTextDiff;
import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
@@ -233,111 +226,6 @@ public abstract class AbstractConflictSearch<T extends Diff> {
}
/**
- * This will be used whenever we check for conflictual MOVEs in order to determine whether we have a
- * pseudo conflict or a real conflict.
- * <p>
- * Namely, this will retrieve the value of the given {@code feature} on the right and left sides of the
- * given {@code match}, then check whether the two given values are on the same index.
- * </p>
- * <p>
- * Note that no sanity checks will be made on either the match's sides or the feature.
- * </p>
- *
- * @param match
- * Match for which we need to check a feature.
- * @param feature
- * The feature which values we need to check.
- * @param value1
- * First of the two values which index we are to compare.
- * @param value2
- * Second of the two values which index we are to compare.
- * @return {@code true} if the two given values are located at the same index in the given feature's
- * values list, {@code false} otherwise.
- */
- protected boolean matchingIndices(Match match, EStructuralFeature feature, Object value1, Object value2) {
- boolean matching = false;
- if (feature.isMany()) {
- @SuppressWarnings("unchecked")
- final List<Object> leftValues = (List<Object>)ReferenceUtil.safeEGet(match.getLeft(), feature);
- @SuppressWarnings("unchecked")
- final List<Object> rightValues = (List<Object>)ReferenceUtil.safeEGet(match.getRight(), feature);
-
- // FIXME the detection _will_ fail for non-unique lists with multiple identical values...
- int leftIndex = -1;
- int rightIndex = -1;
- for (int i = 0; i < leftValues.size(); i++) {
- final Object left = leftValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(left, value1)) {
- break;
- } else if (hasDiff(match, feature, left) || hasDeleteDiff(match, feature, left)) {
- // Do not increment.
- } else {
- leftIndex++;
- }
- }
- for (int i = 0; i < rightValues.size(); i++) {
- final Object right = rightValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(right, value2)) {
- break;
- } else if (hasDiff(match, feature, right) || hasDeleteDiff(match, feature, right)) {
- // Do not increment.
- } else {
- rightIndex++;
- }
- }
- matching = leftIndex == rightIndex;
- } else {
- matching = true;
- }
- return matching;
- }
-
- /**
- * Checks whether the given {@code match} presents a difference of any kind on the given {@code feature}'s
- * {@code value}.
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have changed inside {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- protected boolean hasDiff(Match match, EStructuralFeature feature, Object value) {
- return Iterables.any(match.getDifferences(), and(onFeature(feature.getName()), valueIs(value)));
- }
-
- /**
- * Checks whether the given {@code value} has been deleted from the given {@code feature} of {@code match}
- * .
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have been removed from {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- protected boolean hasDeleteDiff(Match match, EStructuralFeature feature, Object value) {
- checkArgument(match.getComparison() == comparison);
- final Object expectedValue;
- if (value instanceof EObject && comparison.isThreeWay()) {
- final Match valueMatch = comparison.getMatch((EObject)value);
- if (valueMatch != null) {
- expectedValue = valueMatch.getOrigin();
- } else {
- expectedValue = value;
- }
- } else {
- expectedValue = value;
- }
- return Iterables.any(match.getDifferences(),
- and(onFeature(feature.getName()), valueIs(expectedValue), ofKind(DELETE)));
- }
-
- /**
* This will be called whenever we detect a new conflict in order to create (or update) the actual
* association.
*
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
index 30270e033..ba39f3142 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
@@ -21,6 +21,7 @@ import static org.eclipse.emf.compare.DifferenceKind.MOVE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java
index ddaa96e2b..30d8c7523 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java
@@ -23,6 +23,7 @@ import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueMatches;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java
index c3bb489f9..b42c2e5b0 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java
@@ -22,6 +22,7 @@ import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueMatches;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java
index 185b618ac..0a220f043 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java
@@ -21,6 +21,7 @@ import static org.eclipse.emf.compare.DifferenceKind.MOVE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java
index d005ebfb6..1c480d426 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java
@@ -19,6 +19,8 @@ import static com.google.common.base.Predicates.not;
import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.any;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.DifferenceKind.ADD;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isDeleteOrUnsetDiff;
import static org.eclipse.emf.compare.internal.utils.DiffUtil.getAllAtomicRefiningDiffs;
import static org.eclipse.emf.compare.internal.utils.DiffUtil.getAllRefiningDiffs;
@@ -350,6 +352,30 @@ public final class EMFComparePredicates {
}
/**
+ * Indicates whether a diff is part of a real add/add conflict.
+ *
+ * @return a predicate to check if a diff belongs to an add/add conflict.
+ * @since 3.4
+ */
+ public static Predicate<Diff> isInRealAddAddConflict() {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff input) {
+ Conflict conflict = input.getConflict();
+ if (conflict != null) {
+ if (conflict.getKind() != REAL) {
+ return false;
+ } else {
+ if (all(conflict.getDifferences(), ofKind(ADD))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ };
+ }
+
+ /**
* This predicate can be used to check whether a given Diff represents the deletion of a value from a
* multi-valued reference going by {@code referenceName} on an EObject which name matches
* {@code qualifiedName}.
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java
index c50133d1c..d8a526b16 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java
@@ -14,12 +14,18 @@ package org.eclipse.emf.compare.utils;
import static com.google.common.base.Predicates.and;
import static org.eclipse.emf.compare.DifferenceKind.ADD;
import static org.eclipse.emf.compare.DifferenceKind.DELETE;
+import static org.eclipse.emf.compare.DifferenceSource.LEFT;
+import static org.eclipse.emf.compare.DifferenceSource.RIGHT;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueIs;
import static org.eclipse.emf.compare.utils.ReferenceUtil.getAsList;
import com.google.common.collect.Iterables;
+import java.util.List;
+
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Comparison;
@@ -74,6 +80,127 @@ public final class MatchUtil {
}
/**
+ * This will be used whenever we check for conflictual MOVEs in order to determine whether we have a
+ * pseudo conflict or a real conflict.
+ * <p>
+ * Namely, this will retrieve the value of the given {@code feature} on the right and left sides of the
+ * given {@code match}, then check whether the two given values are on the same index.
+ * </p>
+ * <p>
+ * Note that no sanity checks will be made on either the match's sides or the feature.
+ * </p>
+ *
+ * @param match
+ * Match for which we need to check a feature.
+ * @param feature
+ * The feature which values we need to check.
+ * @param value1
+ * First of the two values which index we are to compare.
+ * @param value2
+ * Second of the two values which index we are to compare.
+ * @return {@code true} if the two given values are located at the same index in the given feature's
+ * values list, {@code false} otherwise.
+ * @since 3.4
+ */
+ public static boolean matchingIndices(Match match, EStructuralFeature feature, Object value1,
+ Object value2) {
+ boolean matching = false;
+ if (feature.isMany()) {
+ // FIXME the detection _will_ fail for non-unique lists with multiple identical values...
+ int leftIndex = computeIndex(match, feature, value1, LEFT);
+ int rightIndex = computeIndex(match, feature, value2, RIGHT);
+ matching = leftIndex == rightIndex;
+ } else {
+ matching = true;
+ }
+ return matching;
+ }
+
+ /**
+ * Compute the index of an object in the list of elements of a given match+feature on a given side. This
+ * index is computed without taking objects that have a diff into account, except if this diff is an ADD.
+ *
+ * @param match
+ * The match
+ * @param feature
+ * The structural feature
+ * @param value
+ * The object the index of which must be computed
+ * @param side
+ * The side on which to compute the index
+ * @return The index of the given object.
+ * @since 3.4
+ */
+ public static int computeIndex(Match match, EStructuralFeature feature, Object value,
+ DifferenceSource side) {
+ Comparison comparison = match.getComparison();
+ int result = -1;
+ @SuppressWarnings("unchecked")
+ final List<Object> sideValues = (List<Object>)ReferenceUtil
+ .safeEGet(MatchUtil.getMatchedObject(match, side), feature);
+ for (int i = 0; i < sideValues.size(); i++) {
+ final Object sideObject = sideValues.get(i);
+ if (comparison.getEqualityHelper().matchingValues(sideObject, value)) {
+ break;
+ } else if ((hasDiff(match, feature, sideObject) && match.getOrigin() != null)
+ || hasDeleteDiff(match, feature, sideObject)) {
+ // Do not increment.
+ } else {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks whether the given {@code value} has been deleted from the given {@code feature} of {@code match}
+ * .
+ *
+ * @param match
+ * The match which differences we'll check.
+ * @param feature
+ * The feature on which we expect a difference.
+ * @param value
+ * The value we expect to have been removed from {@code feature}.
+ * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
+ * @since 3.4
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean hasDeleteDiff(Match match, EStructuralFeature feature, Object value) {
+ Comparison comparison = match.getComparison();
+ final Object expectedValue;
+ if (value instanceof EObject && comparison.isThreeWay()) {
+ final Match valueMatch = comparison.getMatch((EObject)value);
+ if (valueMatch != null) {
+ expectedValue = valueMatch.getOrigin();
+ } else {
+ expectedValue = value;
+ }
+ } else {
+ expectedValue = value;
+ }
+ return Iterables.any(match.getDifferences(),
+ and(onFeature(feature.getName()), valueIs(expectedValue), ofKind(DELETE)));
+ }
+
+ /**
+ * Checks whether the given {@code match} presents a difference of any kind on the given {@code feature}'s
+ * {@code value}.
+ *
+ * @param match
+ * The match which differences we'll check.
+ * @param feature
+ * The feature on which we expect a difference.
+ * @param value
+ * The value we expect to have changed inside {@code feature}.
+ * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
+ * @since 3.4
+ */
+ public static boolean hasDiff(Match match, EStructuralFeature feature, Object value) {
+ return Iterables.any(match.getDifferences(), and(onFeature(feature.getName()), valueIs(value)));
+ }
+
+ /**
* From a given mono-valued reference change, get the origin value.
*
* @param comparison

Back to the top