Add EcoreCopier to ensure correct implementation of EGraphImpl.copy()
Change-Id: Ie371028f75f536c60320786b34b0ec62ead68347
diff --git a/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/impl/EGraphImpl.java b/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/impl/EGraphImpl.java
index 4da5384..0c4c799 100644
--- a/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/impl/EGraphImpl.java
+++ b/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/impl/EGraphImpl.java
@@ -26,11 +26,13 @@
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.emf.henshin.interpreter.EGraph;
+import org.eclipse.emf.henshin.interpreter.util.EcoreCopier;
import org.eclipse.emf.henshin.interpreter.util.InterpreterUtil;
/**
@@ -417,7 +419,12 @@
@Override
public EGraph copy(Map<EObject, EObject> copies) {
if (copies==null) {
- Copier copier = new Copier();
+ Copier copier = null;
+ if (packages.contains(EcorePackage.eINSTANCE)) {
+ copier = new EcoreCopier();
+ } else {
+ copier = new Copier();
+ }
copier.copyAll(getRoots());
copier.copyReferences();
copies = copier;
diff --git a/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/util/EcoreCopier.java b/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/util/EcoreCopier.java
new file mode 100644
index 0000000..29beac4
--- /dev/null
+++ b/plugins/org.eclipse.emf.henshin.interpreter/src/org/eclipse/emf/henshin/interpreter/util/EcoreCopier.java
@@ -0,0 +1,118 @@
+package org.eclipse.emf.henshin.interpreter.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EGenericType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.ETypedElement;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
+
+/**
+ * A copier that correctly handles copying of types and generic types in
+ * {@link ETypedElement} instances.
+ *
+ * @author Steffen Zschaler
+ */
+@SuppressWarnings("serial")
+public class EcoreCopier extends Copier {
+
+ public EcoreCopier() {
+ super();
+ }
+
+ public EcoreCopier(boolean resolveProxies) {
+ super(resolveProxies);
+ }
+
+ public EcoreCopier(boolean resolveProxies, boolean useOriginalReferences) {
+ super(resolveProxies, useOriginalReferences);
+ }
+
+ /**
+ * Does everything the super method does, but also makes sure implicitly created
+ * types are stored in the copy map.
+ *
+ * @see org.eclipse.emf.ecore.util.EcoreUtil.Copier#copyContainment(org.eclipse.emf.ecore.EReference,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ protected void copyContainment(EReference eReference, EObject eObject, EObject copyEObject) {
+ super.copyContainment(eReference, eObject, copyEObject);
+
+ if (eObject.eIsSet(eReference)) {
+ if (eReference == EcorePackage.Literals.ETYPED_ELEMENT__EGENERIC_TYPE) {
+ // If this object has an actual generic type, setting it in the copy will have
+ // created a copy of the `eType`. We need to make sure that copy shows up in our
+ // map
+ // TODO: Probably needs more testing: we really would want to make sure this is
+ // wired up to the type we may already have copied, need to make sure this is
+ // happening...
+ if (!containsKey((EObject) eObject.eGet(EcorePackage.Literals.ETYPED_ELEMENT__ETYPE, resolveProxies))) {
+ put((EObject) eObject.eGet(EcorePackage.Literals.ETYPED_ELEMENT__ETYPE, resolveProxies),
+ (EObject) copyEObject.eGet(EcorePackage.Literals.ETYPED_ELEMENT__ETYPE, resolveProxies));
+ }
+ } else if (eReference == EcorePackage.Literals.ECLASS__EGENERIC_SUPER_TYPES) {
+ for (int i = 0, size = ((EClass) eObject).getESuperTypes().size(); i < size; i++) {
+ EClass superType = ((EClass) eObject).getESuperTypes().get(i);
+ if (!containsKey(superType)) {
+ put(superType, ((EClass) copyEObject).getESuperTypes().get(i));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Used to store copies created when copying references
+ */
+ private Map<EObject, EObject> lateCopies;
+
+ /**
+ * Does everything the super method does, but treats eType and eGenericType
+ * specially.
+ *
+ * @see org.eclipse.emf.ecore.util.EcoreUtil.Copier#copyReference(org.eclipse.emf.ecore.EReference,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
+ */
+ @Override
+ protected void copyReference(EReference eReference, EObject eObject, EObject copyEObject) {
+ super.copyReference(eReference, eObject, copyEObject);
+
+ if (eObject.eIsSet(eReference)) {
+ if (eReference == EcorePackage.Literals.ETYPED_ELEMENT__ETYPE) {
+ // In this case, this will have implicitly copied the generic type, so need to
+ // add it to the map
+ lateCopies.put(
+ (EObject) eObject.eGet(EcorePackage.Literals.ETYPED_ELEMENT__EGENERIC_TYPE, resolveProxies),
+ (EObject) copyEObject.eGet(EcorePackage.Literals.ETYPED_ELEMENT__EGENERIC_TYPE,
+ resolveProxies));
+ }
+ else if (eReference == EcorePackage.Literals.ECLASS__ESUPER_TYPES) {
+ for (int i = 0, size = ((EClass)eObject).getEGenericSuperTypes().size(); i < size; i++) {
+ EGenericType eSuperGeneric = ((EClass)eObject).getEGenericSuperTypes().get(i);
+ lateCopies.put (eSuperGeneric, ((EClass)copyEObject).getEGenericSuperTypes().get(i));
+ }
+ }
+ }
+ }
+
+ /*
+ * Need to make sure that we don't change the copy map while
+ * super.copyReferences is iterating over it
+ *
+ * @see org.eclipse.emf.ecore.util.EcoreUtil.Copier#copyReferences()
+ */
+ @Override
+ public void copyReferences() {
+ lateCopies = new LinkedHashMap<>();
+
+ super.copyReferences();
+
+ putAll(lateCopies);
+ lateCopies = null;
+ }
+}
\ No newline at end of file