Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Delaigue2016-10-13 03:54:27 -0400
committerLaurent Delaigue2016-10-13 06:37:31 -0400
commit3c7d3d74422aa061acf2db09586db94088136e61 (patch)
tree7a468249e80b8f0b9eb6cc5d5bdd53a8c3d610c3
parent78e37cb0bbd9d806af97dfdae8f48db30a5d1cf7 (diff)
downloadorg.eclipse.emf.compare-3c7d3d74422aa061acf2db09586db94088136e61.tar.gz
org.eclipse.emf.compare-3c7d3d74422aa061acf2db09586db94088136e61.tar.xz
org.eclipse.emf.compare-3c7d3d74422aa061acf2db09586db94088136e61.zip
[501864] Refactoring of group providers & filters
Diffs that have no real conflict (direct or indirect) and only some pseudo-conflicts (but also non-conflicting refining diffs) only appear in the side group. Also add javadoc to describe the expected behaviour of the group provider 'by side' and some unit tests for predicates. Change-Id: I3d02172b1c77199ea0904459b196289b19db35d6 Signed-off-by: Laurent Delaigue <laurent.delaigue@obeo.fr>
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java8
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java25
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java44
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java278
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java11
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java182
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java2
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java5
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java77
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java66
10 files changed, 506 insertions, 192 deletions
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java
index 9e064ff72..b3947caf2 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java
@@ -32,8 +32,8 @@ import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.Stru
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.TechnicalitiesFilter;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.BasicDifferenceGroupImpl;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.CompositeConflict;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl.CompositeConflict;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.ConflictNode;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.DiffNode;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.MatchNode;
@@ -355,7 +355,7 @@ public class ConflictsGroupTest extends AbstractTestTreeNodeItemProviderAdapter
* href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
*/
@Test
- public void testRefinedDiffsWithOnlyOnePseudoConflictAreInConflictGroupAndDiffGroup() {
+ public void testRefinedDiffsWithOnlyOnePseudoConflictAreInDiffGroupOnly() {
ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
// Create pseudo conflict
@@ -403,7 +403,7 @@ public class ConflictsGroupTest extends AbstractTestTreeNodeItemProviderAdapter
assertEquals(1, diffNodesLeftFiltered.size());
final List<? extends TreeNode> subDiffNodesLeftFiltered = applyTechnicalitiesFilter(
diffNodesLeftFiltered.get(0).getChildren());
- assertEquals(1, subDiffNodesLeftFiltered.size());
+ assertEquals(2, subDiffNodesLeftFiltered.size());
// Build right side
final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
@@ -422,7 +422,7 @@ public class ConflictsGroupTest extends AbstractTestTreeNodeItemProviderAdapter
assertEquals(1, diffNodesRightFiltered.size());
final List<? extends TreeNode> subDiffNodesRightFiltered = applyTechnicalitiesFilter(
diffNodesRightFiltered.get(0).getChildren());
- assertEquals(1, subDiffNodesRightFiltered.size());
+ assertEquals(2, subDiffNodesRightFiltered.size());
}
/**
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java
index e271b0288..95f973a3c 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java
@@ -19,6 +19,23 @@ import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
+/**
+ * This test scenario creates a comparison like this:
+ * <ul>
+ * <li>diff1 (LEFT), refined by
+ * <ul>
+ * <li>diff1a (LEFT)</li>
+ * <li>diff1b (RIGHT)</li>
+ * </ul>
+ * </li>
+ * <li>diff2 (RIGHT), refined by
+ * <ul>
+ * <li>diff2a (LEFT)</li>
+ * <li>diff2b (RIGHT)</li>
+ * </ul>
+ * </li>
+ * </ul>
+ */
public class ConflictsGroupWithRefinedDiffTestScenario {
private static final CompareFactory FACTORY = CompareFactory.eINSTANCE;
@@ -73,6 +90,14 @@ public class ConflictsGroupWithRefinedDiffTestScenario {
comparison.getMatches().add(match1);
}
+ /**
+ * Add a conflict between 2 existing differences of this scenario's comparison.
+ *
+ * @param conflictingDiff1
+ * @param conflictingDiff2
+ * @param kind
+ * @return The created conflict.
+ */
Conflict addConflict(Diff conflictingDiff1, Diff conflictingDiff2, ConflictKind kind) {
final Conflict conflict = FACTORY.createConflict();
conflict.getDifferences().add(conflictingDiff1);
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java
index 3f6ca3871..2fcaa5c5a 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java
@@ -12,14 +12,16 @@
*******************************************************************************/
package org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterators.any;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefiningDiffs;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.allAtomicRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasNoDirectOrIndirectConflict;
import com.google.common.base.Predicate;
-import org.eclipse.emf.compare.ConflictKind;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.FeatureMapChange;
import org.eclipse.emf.compare.Match;
@@ -42,16 +44,6 @@ import org.eclipse.emf.edit.tree.TreeNode;
public class TechnicalitiesFilter extends AbstractDifferenceFilter {
/**
- * The predicate use by this filter when it is selected.
- */
- private static final Predicate<? super EObject> PREDICATE_WHEN_SELECTED = new Predicate<EObject>() {
- public boolean apply(EObject input) {
- return PREDICATE_EMPTY_MATCH_RESOURCES.apply(input) || PREDICATE_FEATURE_MAP.apply(input)
- || PREDICATE_IDENTICAL_ELEMENTS.apply(input) || PREDICATE_PSEUDO_CONFLICT.apply(input);
- }
- };
-
- /**
* The predicate use to filter empty match resources.
*/
private static final Predicate<? super EObject> PREDICATE_EMPTY_MATCH_RESOURCES = new Predicate<EObject>() {
@@ -95,7 +87,7 @@ public class TechnicalitiesFilter extends AbstractDifferenceFilter {
if (data instanceof Diff) {
Diff diff = (Diff)data;
if (diff.getMatch().getComparison().isThreeWay()) {
- ret = hasDirectOrIndirectPseudoConflictOnly(diff);
+ ret = isConsideredAsPseudoConflicting(diff);
}
}
}
@@ -104,19 +96,17 @@ public class TechnicalitiesFilter extends AbstractDifferenceFilter {
};
/**
- * Specifies whether the given diff has a direct or indirect pseudo conflict, but not a direct or indirect
- * real conflict.
+ * Specifies whether the given diff can be considered as part of a pseudo conflict, but not of a real
+ * conflict.
*
* @param diff
* The diff to check.
- * @return <code>true</code> if it only has a direct or indirect pseudo conflict, <code>false</code>
- * otherwise.
+ * @return <code>true</code> if it has a direct pseudo-conflict or of all its atomic refining diffs are in
+ * pseudo-conflict.
*/
- private static boolean hasDirectOrIndirectPseudoConflictOnly(Diff diff) {
- return hasDirectOrIndirectConflict(ConflictKind.PSEUDO).apply(diff)
- && !hasDirectOrIndirectConflict(ConflictKind.REAL).apply(diff)
- && !anyRefiningDiffs(hasNoDirectOrIndirectConflict(ConflictKind.REAL, ConflictKind.PSEUDO))
- .apply(diff);
+ private static boolean isConsideredAsPseudoConflicting(Diff diff) {
+ return allAtomicRefining(hasConflict(PSEUDO)).apply(diff)
+ && hasNoDirectOrIndirectConflict(REAL).apply(diff);
}
/**
@@ -136,6 +126,14 @@ public class TechnicalitiesFilter extends AbstractDifferenceFilter {
};
/**
+ * The predicate use by this filter when it is selected.
+ */
+ @SuppressWarnings("unchecked")
+ private static final Predicate<? super EObject> PREDICATE_WHEN_SELECTED = or(
+ PREDICATE_EMPTY_MATCH_RESOURCES, PREDICATE_FEATURE_MAP, PREDICATE_IDENTICAL_ELEMENTS,
+ PREDICATE_PSEUDO_CONFLICT);
+
+ /**
* Predicate to know if the given TreeNode is a diff.
*/
private static final Predicate<EObject> DATA_IS_DIFF = new Predicate<EObject>() {
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java
index 33d722705..60664fa94 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java
@@ -16,23 +16,28 @@ package org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterators.concat;
import static com.google.common.collect.Iterators.filter;
import static com.google.common.collect.Iterators.transform;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefiningDiffs;
+import static java.util.Collections.unmodifiableSet;
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.internal.utils.DiffUtil.getRootRefinedDiffs;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.allAtomicRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.containsConflictOfTypes;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasNoDirectOrIndirectConflict;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasState;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Collection;
@@ -63,7 +68,6 @@ import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.Confli
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.AbstractDifferenceGroupProvider;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroup;
import org.eclipse.emf.compare.scope.IComparisonScope;
-import org.eclipse.emf.compare.utils.EMFComparePredicates;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
@@ -72,6 +76,45 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
* This implementation of a
* {@link org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider} will be used to
* group the differences by their {@link DifferenceSource side} : left, right and conflicts.
+ * <p>
+ * The table below describes the location of a diff depending on its status and that of its refining diffs
+ * (whether all or some of them are in a real/pseudo conflict). <br/>
+ * <br/>
+ * <table style="border-collapse:collapse;">
+ * <thead>
+ * <tr>
+ * <th rowspan="2"></th>
+ * <th colspan="2" style="border:1px solid;">Real Conflicts</th>
+ * <th colspan="2" style="border:1px solid;">Pseudo-Conflicts</th>
+ * <th style="border:1px solid;">No Conflict</th>
+ * </tr>
+ * <tr>
+ * <th style="border:1px solid;">All</th>
+ * <th style="border:1px solid;">Some</th>
+ * <th style="border:1px solid;">All</th>
+ * <th style="border:1px solid;">Some</th>
+ * <th style="border:1px solid;">All</th>
+ * </tr>
+ * </thead> <tbody>
+ * <tr>
+ * <td style="border:1px solid; padding:0 2px;">Tech. filter ON</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict (hidden)</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * </tr>
+ * <tr>
+ * <td style="border:1px solid; padding:0 2px;">Tech. filter OFF</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * </p>
*
* @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
* @since 4.0
@@ -83,10 +126,9 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
* diffs that do not have a direct or indirect real conflict and that do not have only pseudo conflicts.
*/
public static final Predicate<? super Diff> DEFAULT_DIFF_GROUP_FILTER_PREDICATE = and(
- not(hasDirectOrIndirectConflict(ConflictKind.REAL)),
- not(and(anyRefiningDiffs(hasConflict(ConflictKind.PSEUDO)), not(anyRefiningDiffs(
- hasNoDirectOrIndirectConflict(ConflictKind.PSEUDO, ConflictKind.REAL))))));
-
+ not(hasConflict(REAL, PSEUDO)),
+ not(or(anyRefining(hasConflict(REAL)), allAtomicRefining(hasConflict(PSEUDO)))));
+
/**
* {@inheritDoc}
*
@@ -113,7 +155,7 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
*/
private static final Predicate<? super Diff> DEFAULT_CONFLICT_GROUP_FILTER_PREDICATE = hasConflict(
ConflictKind.REAL, ConflictKind.PSEUDO);
-
+
/**
* Conflict groups to show in SMV.
*/
@@ -150,7 +192,7 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
ECrossReferenceAdapter crossReferenceAdapter) {
super(comparison, DEFAULT_CONFLICT_GROUP_FILTER_PREDICATE, name, crossReferenceAdapter);
}
-
+
/**
* In conflicts, a special case must be handled for refining diffs: If they are not part of the same
* conflict then they should not be in the same group as the refined diff.
@@ -216,121 +258,6 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
}
/**
- * This extension of {@link Conflict} is used to handle {@link Diff#getRefinedBy() refined} diffs and
- * to join conflicts for the SMV. If refining diffs are part of a conflict, we show their refined
- * diffs instead. As we show refined diffs instead of the refining diffs, multiple conflicts may
- * consequently include the same refined diffs. To avoid that, this extension of a conflict also joins
- * such overlapping conflicts.
- *
- * @author <a href="mailto:tmayerhofer@eclipsesource.com">Tanja Mayerhofer</a>
- */
- public static class CompositeConflict extends ConflictImpl {
-
- /** The joined conflicts. */
- private Set<Conflict> conflicts = new LinkedHashSet<Conflict>();
-
- /** The diffs of all composed conflicts. */
- private EList<Diff> diffs = new BasicEList<Diff>();
-
- /** The conflict kind of this composite conflict. */
- private ConflictKind conflictKind = ConflictKind.REAL;
-
- /**
- * Creates a new composite conflict for the given conflict.
- *
- * @param conflict
- * The conflict to create a composite conflict for.
- */
- public CompositeConflict(Conflict conflict) {
- this.conflicts.add(checkNotNull(conflict));
- this.conflictKind = conflict.getKind();
- this.diffs.addAll(computeRefinedDiffs(conflict));
- }
-
- /**
- * Computes the refined diffs of the conflict. In particular, refining diffs are replaced by
- * refined diffs.
- *
- * @param conflict
- * The conflict to compute its refined diffs for.
- * @return The set of refined diffs of the conflict
- */
- private Set<Diff> computeRefinedDiffs(Conflict conflict) {
- final LinkedHashSet<Diff> computedDiffs = new LinkedHashSet<Diff>();
- for (Diff diff : conflict.getDifferences()) {
- if (diff.getRefines().isEmpty()) {
- computedDiffs.add(diff);
- } else {
- computedDiffs.addAll(getRootRefinedDiffs(diff));
- }
- }
- return computedDiffs;
- }
-
- /**
- * Determines the leaf refined diff of a refining diff, i.e., a refined diff that is not refining
- * another diff.
- *
- * @param diff
- * The diff for which the leaf refined diff is to be determined
- * @return The leaf refined diff of the provided (refining diff)
- */
- private List<Diff> getRootRefinedDiffs(Diff diff) {
- final List<Diff> rootRefinedDiffs = newArrayList();
- for (Diff refinedDiff : diff.getRefines()) {
- if (refinedDiff.getRefines().isEmpty()) {
- rootRefinedDiffs.add(refinedDiff);
- } else {
- rootRefinedDiffs.addAll(getRootRefinedDiffs(refinedDiff));
- }
- }
- return rootRefinedDiffs;
- }
-
- @Override
- public ConflictKind getKind() {
- return this.conflictKind;
- }
-
- @Override
- public EList<Diff> getDifferences() {
- return this.diffs;
- }
-
- /**
- * Returns the joined conflicts.
- *
- * @return The joined conflicts
- */
- public Set<Conflict> getConflicts() {
- return conflicts;
- }
-
- /**
- * Joins the provided composite conflict with this composite conflict.
- *
- * @param conflict
- * The conflict to be joined with this composite conflict
- */
- public void join(CompositeConflict conflict) {
- final LinkedHashSet<Diff> joinedDiffs = new LinkedHashSet<Diff>(
- Sets.union(new LinkedHashSet<Diff>(this.diffs),
- new LinkedHashSet<Diff>(conflict.getDifferences())));
- this.diffs.clear();
- this.diffs.addAll(joinedDiffs);
- this.conflicts.addAll(conflict.getConflicts());
-
- final Conflict realConflict = Iterators.find(this.conflicts.iterator(),
- EMFComparePredicates.containsConflictOfTypes(ConflictKind.REAL), null);
- if (realConflict != null) {
- this.conflictKind = ConflictKind.REAL;
- } else {
- this.conflictKind = ConflictKind.PSEUDO;
- }
- }
- }
-
- /**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.BasicDifferenceGroupImpl#getStyledName()
@@ -353,10 +280,105 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
}
/**
- * {@inheritDoc}
+ * This extension of {@link Conflict} is used to handle {@link Diff#getRefinedBy() refined} diffs and to
+ * join conflicts for the SMV. If refining diffs are part of a conflict, we show their refined diffs
+ * instead. As we show refined diffs instead of the refining diffs, multiple conflicts may consequently
+ * include the same refined diffs. To avoid that, this extension of a conflict also joins such overlapping
+ * conflicts.
*
- * @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.AbstractBuildingDifferenceGroupProvider#buildGroups(org.eclipse.emf.compare.Comparison)
+ * @author <a href="mailto:tmayerhofer@eclipsesource.com">Tanja Mayerhofer</a>
*/
+ public static class CompositeConflict extends ConflictImpl {
+
+ /** The joined conflicts. */
+ private Set<Conflict> conflicts = new LinkedHashSet<Conflict>();
+
+ /** The diffs of all composed conflicts. */
+ private EList<Diff> diffs = new BasicEList<Diff>();
+
+ /** The conflict kind of this composite conflict. */
+ private ConflictKind conflictKind = ConflictKind.REAL;
+
+ /**
+ * Creates a new composite conflict for the given conflict.
+ *
+ * @param conflict
+ * The conflict to create a composite conflict for, must not be <code>null</code> and must
+ * have a non-<code>null</code> {@link Conflict#getKind() kind}.
+ */
+ public CompositeConflict(Conflict conflict) {
+ conflicts.add(checkNotNull(conflict));
+ conflictKind = checkNotNull(conflict.getKind());
+ diffs.addAll(computeRefinedDiffs(conflict));
+ }
+
+ /**
+ * Computes the refined diffs of the conflict. In particular, refining diffs are replaced by refined
+ * diffs.
+ *
+ * @param conflict
+ * The conflict to compute its refined diffs for.
+ * @return The set of refined diffs of the conflict
+ */
+ private Set<Diff> computeRefinedDiffs(Conflict conflict) {
+ Set<Diff> computedDiffs = new LinkedHashSet<Diff>();
+ for (Diff diff : conflict.getDifferences()) {
+ if (diff.getRefines().isEmpty()) {
+ computedDiffs.add(diff);
+ } else {
+ computedDiffs.addAll(getRootRefinedDiffs(diff));
+ }
+ }
+ return computedDiffs;
+ }
+
+ @Override
+ public ConflictKind getKind() {
+ return conflictKind;
+ }
+
+ /**
+ * Returns an EList built by aggregating the diffs of all the aggregated conflicts.
+ * <p>
+ * <b>This list is not supposed to be used for update, since modifying this list will not modify the
+ * underlying conflicts.</b>
+ * </p>
+ */
+ @Override
+ public EList<Diff> getDifferences() {
+ return diffs;
+ }
+
+ /**
+ * Returns an unmodifiable view of the joined conflicts.
+ *
+ * @return An unmodifiable view of the joined conflicts, never <code>null</code> nor empty.
+ */
+ public Set<Conflict> getConflicts() {
+ return unmodifiableSet(conflicts);
+ }
+
+ /**
+ * Joins the provided composite conflict with this composite conflict.
+ *
+ * @param conflict
+ * The conflict to be joined with this composite conflict
+ */
+ public void join(CompositeConflict conflict) {
+ Set<Diff> currentDiffSet = new LinkedHashSet<Diff>(diffs);
+ Set<Diff> otherDiffSet = new LinkedHashSet<Diff>(conflict.getDifferences());
+ SetView<Diff> newDiffs = Sets.difference(otherDiffSet, currentDiffSet);
+ diffs.addAll(newDiffs);
+ if (conflicts.addAll(conflict.getConflicts()) && conflictKind != REAL) {
+ if (any(conflicts, containsConflictOfTypes(REAL))) {
+ conflictKind = REAL;
+ } else {
+ conflictKind = PSEUDO;
+ }
+ }
+ }
+ }
+
@Override
protected Collection<? extends IDifferenceGroup> buildGroups(Comparison comparison2) {
Adapter adapter = EcoreUtil.getAdapter(getComparison().eAdapters(), SideLabelProvider.class);
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
index 38afa7a79..4a1003a90 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
@@ -13,10 +13,6 @@
*******************************************************************************/
package org.eclipse.emf.compare.tests.suite;
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.textui.TestRunner;
-
import org.eclipse.emf.compare.ComparePackage;
import org.eclipse.emf.compare.tests.command.CommandStackTestSuite;
import org.eclipse.emf.compare.tests.conflict.ConflictDetectionTest;
@@ -65,6 +61,7 @@ import org.eclipse.emf.compare.tests.postprocess.PostProcessorTest;
import org.eclipse.emf.compare.tests.req.ReqComputingTest;
import org.eclipse.emf.compare.tests.scope.ComparisonScopeAdapterTest;
import org.eclipse.emf.compare.tests.scope.DefaultComparisonScopeTest;
+import org.eclipse.emf.compare.tests.utils.EMFComparePredicatesTest;
import org.eclipse.emf.compare.tests.utils.EqualityHelperTest;
import org.eclipse.emf.compare.tests.utils.MatchUtilFeatureContainsTest;
import org.eclipse.emf.ecore.EPackage;
@@ -74,6 +71,10 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
/**
* This test suite allows us to launch all tests for EMF Compare at once.
*
@@ -96,7 +97,7 @@ import org.junit.runners.Suite.SuiteClasses;
MultiLineAttributeMergeTest.class, MonitorCancelTest.class, IdentifierEObjectMatcherTest.class,
MatchUtilFeatureContainsTest.class, RefineMergeTest.class, Bug484557ConflictTest.class,
Bug485266_MoveDeleteConflict_Test.class, ResourceAttachmentChangeBug492261.class,
- ComparisonScopeAdapterTest.class, })
+ ComparisonScopeAdapterTest.class, EMFComparePredicatesTest.class, })
public class AllTests {
/**
* Standalone launcher for all of compare's tests.
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java
new file mode 100644
index 000000000..679ba6db1
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.utils;
+
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.base.Predicates.instanceOf;
+import static java.util.Arrays.asList;
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.allAtomicRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasNoDirectOrIndirectConflict;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.CompareFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.ReferenceChange;
+import org.junit.Test;
+
+public class EMFComparePredicatesTest {
+
+ private CompareFactory factory = CompareFactory.eINSTANCE;
+
+ @Test
+ public void testAnyRefiningWithoutRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ ReferenceChange rc1 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(rc1);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(rc1, rc2, rc3));
+
+ assertFalse(anyRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(anyRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertTrue(anyRefining(equalTo((Diff)rc3)).apply(ac));
+ }
+
+ @Test
+ public void testAnyRefiningWithRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ AttributeChange ac1 = factory.createAttributeChange();
+ ReferenceChange rc11 = factory.createReferenceChange();
+ ReferenceChange rc12 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(ac1);
+ diffs.add(rc11);
+ diffs.add(rc12);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(ac1, rc2, rc3));
+ ac1.getRefinedBy().addAll(asList(rc11, rc12));
+
+ assertTrue(anyRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(anyRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertTrue(anyRefining(equalTo((Diff)rc12)).apply(ac));
+ assertFalse(anyRefining(equalTo((Diff)ac)).apply(ac));
+ }
+
+ @Test
+ public void testAllAtomicRefiningWithoutRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ ReferenceChange rc1 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(rc1);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(rc1, rc2, rc3));
+
+ assertFalse(allAtomicRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(allAtomicRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertFalse(allAtomicRefining(equalTo((Diff)rc3)).apply(ac));
+ }
+
+ @Test
+ public void testAllAtomicRefiningWithRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ AttributeChange ac1 = factory.createAttributeChange();
+ ReferenceChange rc11 = factory.createReferenceChange();
+ ReferenceChange rc12 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(ac1);
+ diffs.add(rc11);
+ diffs.add(rc12);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(ac1, rc2, rc3));
+ ac1.getRefinedBy().addAll(asList(rc11, rc12));
+
+ assertFalse(allAtomicRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(allAtomicRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertFalse(allAtomicRefining(equalTo((Diff)rc12)).apply(ac));
+ }
+
+ @Test
+ public void testHasDirectOrIndirectConflictForDirectConflict() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+ AttributeChange acl = factory.createAttributeChange();
+ AttributeChange acr = factory.createAttributeChange();
+ rootMatch.getDifferences().addAll(asList(acl, acr));
+ Conflict conflict = factory.createConflict();
+ conflict.setKind(REAL);
+ conflict.getDifferences().addAll(asList(acl, acr));
+ comp.getConflicts().add(conflict);
+
+ assertTrue(hasDirectOrIndirectConflict(REAL).apply(acl));
+ assertTrue(hasDirectOrIndirectConflict(REAL).apply(acr));
+ assertFalse(hasDirectOrIndirectConflict(PSEUDO).apply(acl));
+ assertFalse(hasDirectOrIndirectConflict(PSEUDO).apply(acr));
+
+ assertFalse(hasNoDirectOrIndirectConflict(REAL).apply(acl));
+ assertFalse(hasNoDirectOrIndirectConflict(REAL).apply(acr));
+ assertTrue(hasNoDirectOrIndirectConflict(PSEUDO).apply(acl));
+ assertTrue(hasNoDirectOrIndirectConflict(PSEUDO).apply(acr));
+ }
+
+ @Test
+ public void testHasDirectOrIndirectConflictForIndirectConflict() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+ ReferenceChange rc = factory.createReferenceChange();
+ AttributeChange acl = factory.createAttributeChange();
+ AttributeChange acr = factory.createAttributeChange();
+ rootMatch.getDifferences().addAll(asList(rc, acl, acr));
+ rc.getRefinedBy().addAll(asList(acl));
+ Conflict conflict = factory.createConflict();
+ conflict.setKind(REAL);
+ conflict.getDifferences().addAll(asList(acl, acr));
+ comp.getConflicts().add(conflict);
+
+ assertTrue(hasDirectOrIndirectConflict(REAL).apply(rc));
+ assertFalse(hasDirectOrIndirectConflict(PSEUDO).apply(rc));
+ assertFalse(hasNoDirectOrIndirectConflict(REAL).apply(rc));
+ assertTrue(hasNoDirectOrIndirectConflict(PSEUDO).apply(rc));
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java
index fc072b076..bea16fbe8 100644
--- a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java
@@ -27,8 +27,8 @@ import org.eclipse.emf.compare.Conflict;
import org.eclipse.emf.compare.ConflictKind;
import org.eclipse.emf.compare.provider.spec.CompareItemProviderAdapterFactorySpec;
import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareRCPUIMessages;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.CompositeConflict;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl.CompositeConflict;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.ConflictNode;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.DiffNode;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.MatchNode;
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java
index b9341c0c5..fc0317205 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java
@@ -14,7 +14,7 @@ package org.eclipse.emf.compare.uml2.internal.postprocessor;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.filter;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefinedDiffs;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefined;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
@@ -122,8 +122,7 @@ public class MultiplicityElementChangePostProcessor implements IPostProcessor {
*/
private void verifyConflicts(Comparison comparison) {
for (Conflict conflict : comparison.getConflicts()) {
- if (all(conflict.getDifferences(),
- anyRefinedDiffs(instanceOf(MultiplicityElementChange.class)))) {
+ if (all(conflict.getDifferences(), anyRefined(instanceOf(MultiplicityElementChange.class)))) {
final Iterable<Diff> leftDiffs = collectRefinedDiffs(conflict.getLeftDifferences(),
instanceOf(MultiplicityElementChange.class));
for (Diff leftDiff : leftDiffs) {
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
index 7bb3f646f..89f2e2501 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2014 Obeo and others.
+ * Copyright (c) 2012, 2016 Obeo and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.emf.compare.internal.utils;
+import static com.google.common.collect.Lists.newArrayList;
+
import com.google.common.base.Predicate;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Iterables;
@@ -24,6 +26,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@@ -67,6 +70,70 @@ public final class DiffUtil {
}
/**
+ * The set of all the diffs that refine the given diff or one of its refining diffs, recursively.
+ *
+ * @param diff
+ * The diff for which all the refining diffs are seeked
+ * @return A set of all the refining diffs (as opposed to getting only the 1st level of refining diffs
+ * that would be obtained by calling getRefinedBy() on diff.
+ */
+ public static Set<Diff> getAllRefiningDiffs(Diff diff) {
+ Set<Diff> result = new LinkedHashSet<Diff>();
+ if (diff != null) {
+ for (Diff refiningDiff : diff.getRefinedBy()) {
+ result.add(refiningDiff);
+ if (!refiningDiff.getRefinedBy().isEmpty()) {
+ result.addAll(getAllRefiningDiffs(refiningDiff));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Determines the root refined diff of a refining diff, i.e. a refined diff that is not refining another
+ * diff.
+ *
+ * @param diff
+ * The diff for which the root refined diffs are to be determined
+ * @return The root refined diffs of the provided (refining) diff, as a list. Never <code>null</code>.
+ * Empty if the provided diff does not refine any diff.
+ */
+ public static List<Diff> getRootRefinedDiffs(Diff diff) {
+ List<Diff> rootRefinedDiffs = newArrayList();
+ for (Diff refinedDiff : diff.getRefines()) {
+ if (refinedDiff.getRefines().isEmpty()) {
+ rootRefinedDiffs.add(refinedDiff);
+ } else {
+ rootRefinedDiffs.addAll(getRootRefinedDiffs(refinedDiff));
+ }
+ }
+ return rootRefinedDiffs;
+ }
+
+ /**
+ * The set of all the diffs that refine the given diff or one of its refining diffs, recursively.
+ *
+ * @param diff
+ * The diff for which all the refining diffs are seeked
+ * @return A set of all the refining diffs (as opposed to getting only the 1st level of refining diffs
+ * that would be obtained by calling getRefinedBy() on diff.
+ */
+ public static Set<Diff> getAllAtomicRefiningDiffs(Diff diff) {
+ Set<Diff> result = new LinkedHashSet<Diff>();
+ if (diff != null) {
+ for (Diff refiningDiff : diff.getRefinedBy()) {
+ if (refiningDiff.getRefinedBy().isEmpty()) {
+ result.add(refiningDiff);
+ } else {
+ result.addAll(getAllAtomicRefiningDiffs(refiningDiff));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
* Computes the dice coefficient between the two given String's bigrams.
* <p>
* This implementation is case sensitive.
@@ -77,10 +144,10 @@ public final class DiffUtil {
* want the similarity between <code>"v1"</code> and <code>"v2"</code> to be <code>0.5</code> and not
* <code>0</code>. However, we also want <code>"v1"</code> and <code>"v2"</code> to be "more similar" to
* each other than <code>"v"</code> and <code>"v2"</code> and <code>"v1"</code> and <code>"v11"</code> to
- * be "more similar" than <code>"v"</code> and <code>"v11"</code> while this latter also needs to be
- * "less similar" than <code>"v1"</code> and <code>"v2"</code>. This requires a slightly different
- * handling for comparisons with a "single character"-long string than for "two character"-long ones. A
- * set of invariants we wish to meet can be found in the unit tests.
+ * be "more similar" than <code>"v"</code> and <code>"v11"</code> while this latter also needs to be "less
+ * similar" than <code>"v1"</code> and <code>"v2"</code>. This requires a slightly different handling for
+ * comparisons with a "single character"-long string than for "two character"-long ones. A set of
+ * invariants we wish to meet can be found in the unit tests.
* </p>
*
* @param first
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 97d88cf8d..d005ebfb6 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
@@ -16,13 +16,18 @@ package org.eclipse.emf.compare.utils;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.not;
-import static com.google.common.collect.Iterators.any;
+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.internal.utils.ComparisonUtil.isDeleteOrUnsetDiff;
+import static org.eclipse.emf.compare.internal.utils.DiffUtil.getAllAtomicRefiningDiffs;
+import static org.eclipse.emf.compare.internal.utils.DiffUtil.getAllRefiningDiffs;
import com.google.common.base.Predicate;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.Set;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Conflict;
@@ -1111,33 +1116,59 @@ public final class EMFComparePredicates {
}
/**
- * This predicate can be used to check whether any refining diffs of a given diff fulfill the given
+ * This predicate can be used to check whether any refining diff of a given diff fulfills the given
* predicate.
*
* @param predicate
* The predicate to check.
* @return The predicate.
+ * @since 3.4
*/
- public static Predicate<? super Diff> anyRefiningDiffs(final Predicate<? super Diff> predicate) {
+ public static Predicate<Diff> anyRefining(final Predicate<? super Diff> predicate) {
return new Predicate<Diff>() {
- public boolean apply(Diff input) {
- return input != null && any(input.getRefinedBy().iterator(), predicate);
+ public boolean apply(Diff diff) {
+ return diff != null && any(getAllRefiningDiffs(diff), predicate);
}
};
}
/**
- * This predicate can be used to check whether any refined diffs of a given diff fulfill the given
+ * This predicate can be used to check whether any refined diff of a given diff fulfills the given
* predicate.
*
* @param predicate
* The predicate to check.
* @return The predicate.
+ * @since 3.4
*/
- public static Predicate<? super Diff> anyRefinedDiffs(final Predicate<? super Diff> predicate) {
+ public static Predicate<Diff> anyRefined(final Predicate<? super Diff> predicate) {
return new Predicate<Diff>() {
public boolean apply(Diff input) {
- return input != null && any(input.getRefines().iterator(), predicate);
+ return input != null && any(input.getRefines(), predicate);
+ }
+ };
+ }
+
+ /**
+ * This predicate can be used to check whether a diff has refiningDiffs AND all these refining diffs
+ * fulfill the given predicate.
+ * <p>
+ * <b>BEWARE: If the given diff has no refining diff, the predicate returns <code>false</code>.</b>
+ * </p>
+ *
+ * @param predicate
+ * The predicate to check on each 'atomic' (i.e. not refined) refining diff.
+ * @return The predicate.
+ * @since 3.4
+ */
+ public static Predicate<Diff> allAtomicRefining(final Predicate<? super Diff> predicate) {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ Set<Diff> atomicRefiningDiffs = getAllAtomicRefiningDiffs(diff);
+ if (atomicRefiningDiffs.isEmpty()) {
+ return false;
+ }
+ return all(atomicRefiningDiffs, predicate);
}
};
}
@@ -1152,22 +1183,10 @@ public final class EMFComparePredicates {
* @param kinds
* Type(s) of the conflict(s) we seek.
* @return The created predicate.
+ * @since 3.4
*/
public static Predicate<? super Diff> hasDirectOrIndirectConflict(final ConflictKind... kinds) {
- return new Predicate<Diff>() {
- public boolean apply(Diff diff) {
- if (hasConflict(kinds).apply(diff)) {
- return true;
- } else {
- for (ConflictKind kind : kinds) {
- if (anyRefiningDiffs(hasConflict(kind)).apply(diff)) {
- return true;
- }
- }
- }
- return false;
- }
- };
+ return or(hasConflict(kinds), anyRefining(hasConflict(kinds)));
}
/**
@@ -1180,9 +1199,10 @@ public final class EMFComparePredicates {
* @param kinds
* Type(s) of the conflict(s) we seek.
* @return The created predicate.
+ * @since 3.4
*/
public static Predicate<? super Diff> hasNoDirectOrIndirectConflict(final ConflictKind... kinds) {
- return and(not(hasConflict(kinds)), not(anyRefiningDiffs(hasConflict(kinds))));
+ return not(hasDirectOrIndirectConflict(kinds));
}
/**

Back to the top