Bug 566672 - Unclear behavior of IComparison::getDifferences(Role)

Change-Id: I71e9c765b8a786fc7ad860a0cabf07bd56554acf
Signed-off-by: Olivier Constant <olivier.constant@thalesgroup.com>
Also-by: Matthieu Helleboid <matthieu.helleboid@thalesgroup.com>
diff --git a/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/api/IComparison.java b/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/api/IComparison.java
index f423fe2..851feb8 100644
--- a/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/api/IComparison.java
+++ b/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/api/IComparison.java
@@ -74,8 +74,11 @@
   
   /**
    * Return the match for the container of the given match in the given role.
-   * Result is null if and only if there is no container in the corresponding
-   * scope or no element in the role for the given match.
+   * Result is null if and only if
+   * - there is no container in the corresponding scope
+   * - or there is no element in the role for the given match
+   * - or there is such an element but it has been removed from the scope through a
+   *    merge operation.
    * @param match_p a non-null match
    * @param role_p a non-null role
    * @return a potentially null match
@@ -83,13 +86,17 @@
   IMatch<E> getContainerOf(IMatch<E> match_p, Role role_p);
   
   /**
-   * Return the matches for the roots of the TARGET and REFERENCE scopes
+   * Return the matches for the roots of the TARGET and REFERENCE scopes.
+   * The result is based on the current contents of the scope, i.e., it excludes
+   * matches of elements removed from the scope through a merge operation.
    * @return a non-null, potentially empty, unmodifiable ordered set of matches
    */
   List<IMatch<E>> getContents();
   
   /**
-   * Return the matches for the roots of the scope of the given role
+   * Return the matches for the roots of the scope of the given role.
+   * The result is based on the current contents of the scope, i.e., it excludes
+   * matches of elements removed from the scope through a merge operation.
    * @param role_p a non-null role
    * @return a non-null, potentially empty, unmodifiable ordered set of matches
    */
@@ -98,13 +105,17 @@
   /**
    * Return the matches for the contents of the given match in the TARGET and
    * REFERENCE roles. Matches from REFERENCE come first.
+   * The result is based on the current contents of the scope, i.e., it excludes
+   * matches of elements removed from the scope through a merge operation.
    * @param match_p a non-null match
    * @return a non-null, potentially empty, unmodifiable ordered set of matches
    */
   List<IMatch<E>> getContentsOf(IMatch<E> match_p);
   
   /**
-   * Return the matches for the contents of the given match in the given role
+   * Return the matches for the contents of the given match in the given role.
+   * The result is based on the current contents of the scope, i.e., it excludes
+   * matches of elements removed from the scope through a merge operation.
    * @param match_p a non-null match
    * @param role_p a non-null role
    * @return a non-null, potentially empty, unmodifiable ordered set of matches
@@ -112,14 +123,14 @@
   List<IMatch<E>> getContentsOf(IMatch<E> match_p, Role role_p);
   
   /**
-   * Return all differences in the given role.
+   * Return all differences that are due to a presence of data in the given role.
    * This operation cannot be assumed to be efficient.
    * The resulting collection may become obsolete if the comparison is reset.
    * @param role_p a role which is TARGET or REFERENCE
    * @return a non-null, unmodifiable list which may contain duplicates if differences
    *         are not low-level, technical differences
    */
-  List<IDifference<E>> getDifferences(Role role_p);
+  Collection<IDifference<E>> getDifferences(Role role_p);
   
   /**
    * Return the set of duplicate match IDs for the given role, if any.
@@ -170,6 +181,7 @@
   
   /**
    * Return the set of differences which have not been merged.
+   * It is a subset of the union of getDifferences(TARGET) and getDifferences(REFERENCE).
    * The resulting collection may become obsolete if the comparison is reset.
    * @return a non-null, potentially empty, unmodifiable collection
    */
diff --git a/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/gdiffdata/impl/GComparisonImpl.java b/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/gdiffdata/impl/GComparisonImpl.java
index 20d4f07..f4d3c8e 100644
--- a/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/gdiffdata/impl/GComparisonImpl.java
+++ b/plugins/org.eclipse.emf.diffmerge.generic/src/org/eclipse/emf/diffmerge/generic/gdiffdata/impl/GComparisonImpl.java
@@ -777,14 +777,12 @@
    * @see org.eclipse.emf.diffmerge.generic.api.IComparison#getDifferences(org.eclipse.emf.diffmerge.generic.api.Role)
    * @generated NOT
    */
-  public List<IDifference<E>> getDifferences(Role role_p) {
-    List<IDifference<E>> result = new FArrayList<IDifference<E>>();
-    Iterator<IMatch<E>> it = getAllContents(role_p);
-    while (it.hasNext()) {
-      IMatch<E> current = it.next();
-      result.addAll(current.getPresenceDifferencesIn(role_p));
+  public Collection<IDifference<E>> getDifferences(Role role_p) {
+    Collection<IDifference<E>> result = new FHashSet<IDifference<E>>(IEqualityTester.BY_EQUALS);
+    for (IMatch<E> match : getMapping().getContents()) {
+      result.addAll(match.getPresenceDifferencesIn(role_p));
     }
-    return result;
+    return Collections.unmodifiableCollection(result);
   }
 
   /**