496434: Assigning a collection of collections to a many-valued property
results in a ClassCastException 

Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=496434
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java
index b17436a..a624e43 100644
--- a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java
+++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java
@@ -202,7 +202,9 @@
 			}
 			return eCls.getName();
 		} else if (type instanceof Class<?>) {
-			return NATIVE + '!' + ((Class<?>) type).getName();
+			final Class<?> cls = (Class<?>) type;
+			final String nativeTypeName = NativeTypes.typeName(cls);
+			return cls.getName().equals(nativeTypeName) ? NATIVE + '!' + nativeTypeName : nativeTypeName;
 		} else {
 			return type.toString();
 		}
@@ -562,8 +564,8 @@
 		}
 		if (sf.isMany()) {
 			if (!(value instanceof Collection<?>)) {
-				throw new IllegalArgumentException(String.format("Cannot assign %s to multi-valued field %s::%s", value, sf
-						.getEContainingClass().getName(), sf.getName()));
+				throw new IllegalArgumentException(String.format("Cannot assign %s to multi-valued field %s::%s",
+						toPrettyString(value, env), sf.getEContainingClass().getName(), sf.getName()));
 			}
 			setMany(env, eo, sf, (Collection<?>) value);
 		} else {
@@ -772,10 +774,12 @@
 			if (index > -1) {
 				int currentIndex = index;
 				for (Object v : srcValues) {
+					checkValueTypeIsEObject(env, ref, v);
 					addRefValue(env, ref, eo, values, (EObject) v, currentIndex++, allowInterModelReferences);
 				}
 			} else {
 				for (Object v : srcValues) {
+					checkValueTypeIsEObject(env, ref, v);
 					addRefValue(env, ref, eo, values, (EObject) v, -1, allowInterModelReferences);
 				}
 			}
@@ -802,6 +806,24 @@
 	}
 
 	/**
+	 * Checks that the value is an instance of {@link EObject}.
+	 * 
+	 * @param env
+	 *            the current {@link ExecEnv}
+	 * @param ref
+	 *            the {@link EReference} to assign to
+	 * @param v
+	 *            the value to check
+	 */
+	private static void checkValueTypeIsEObject(final ExecEnv env, final EReference ref, final Object v) {
+		if (!(v instanceof EObject)) {
+			throw new IllegalArgumentException(String.format(
+					"Cannot add/remove values of type %s to/from multi-valued field %s::%s",
+					getTypeName(env, v.getClass()), ref.getEContainingClass().getName(), ref.getName()));
+		}
+	}
+
+	/**
 	 * Removes the <code>value</code> from <code>eo.sf</code>. Assumes <code>sf</code> has a multiplicity &gt; 1.
 	 * 
 	 * @param env
@@ -843,6 +865,7 @@
 			final EReference ref = (EReference) sf;
 			final Collection<?> srcValues = ref.isContainment() ? new ArrayList<Object>(value) : value;
 			for (Object v : srcValues) {
+				checkValueTypeIsEObject(env, ref, v);
 				removeRefValue(ref, eo, values, (EObject) v);
 			}
 		} else {
diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/util/tests/EMFTVMUtilTest.java b/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/util/tests/EMFTVMUtilTest.java
index 7b50b96..abbe575 100644
--- a/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/util/tests/EMFTVMUtilTest.java
+++ b/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/util/tests/EMFTVMUtilTest.java
@@ -15,7 +15,13 @@
 import java.lang.reflect.Modifier;
 
 import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EReference;
 import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.m2m.atl.emftvm.CodeBlock;
+import org.eclipse.m2m.atl.emftvm.EmftvmFactory;
+import org.eclipse.m2m.atl.emftvm.EmftvmPackage;
+import org.eclipse.m2m.atl.emftvm.ExecEnv;
+import org.eclipse.m2m.atl.emftvm.Instruction;
 import org.eclipse.m2m.atl.emftvm.util.EMFTVMUtil;
 import org.eclipse.m2m.atl.emftvm.util.LazyCollection;
 import org.eclipse.m2m.atl.emftvm.util.LazyList;
@@ -111,4 +117,65 @@
 		assertEquals(int.class, method.getReturnType());
 	}
 
+	/**
+	 * Test method for
+	 * {@link EMFTVMUtil#set(ExecEnv, org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EStructuralFeature, Object)}.
+	 */
+	public void testSet_Bug496434() {
+		final ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
+		final CodeBlock eo = EmftvmFactory.eINSTANCE.createCodeBlock();
+		final EReference sf = EmftvmPackage.eINSTANCE.getCodeBlock_Code();
+		final LazyList<Instruction> element = new LazyList<Instruction>().append(EmftvmFactory.eINSTANCE.createPusht());
+		final LazyList<LazyList<Instruction>> value = new LazyList<LazyList<Instruction>>().append(element);
+
+		try {
+			EMFTVMUtil.set(env, eo, sf, value);
+			fail("Expected VMException");
+		} catch (IllegalArgumentException e) {
+			assertEquals("Cannot add/remove values of type Sequence to/from multi-valued field CodeBlock::code",
+					e.getMessage());
+		}
+	}
+
+	/**
+	 * Test method for {@link EMFTVMUtil#add(ExecEnv,
+	 * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EStructuralFeature,
+	 * Object, int).
+	 */
+	public void testAdd_Bug496434() {
+		final ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
+		final CodeBlock eo = EmftvmFactory.eINSTANCE.createCodeBlock();
+		final EReference sf = EmftvmPackage.eINSTANCE.getCodeBlock_Code();
+		final LazyList<Instruction> element = new LazyList<Instruction>().append(EmftvmFactory.eINSTANCE.createPusht());
+		final LazyList<LazyList<Instruction>> value = new LazyList<LazyList<Instruction>>().append(element);
+
+		try {
+			EMFTVMUtil.add(env, eo, sf, value, 0);
+			fail("Expected VMException");
+		} catch (IllegalArgumentException e) {
+			assertEquals("Cannot add/remove values of type Sequence to/from multi-valued field CodeBlock::code",
+					e.getMessage());
+		}
+	}
+
+	/**
+	 * Test method for
+	 * {@link EMFTVMUtil#remove(ExecEnv, org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EStructuralFeature, Object)}.
+	 */
+	public void testRemove_Bug496434() {
+		final ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
+		final CodeBlock eo = EmftvmFactory.eINSTANCE.createCodeBlock();
+		final EReference sf = EmftvmPackage.eINSTANCE.getCodeBlock_Code();
+		final LazyList<Instruction> element = new LazyList<Instruction>().append(EmftvmFactory.eINSTANCE.createPusht());
+		final LazyList<LazyList<Instruction>> value = new LazyList<LazyList<Instruction>>().append(element);
+
+		try {
+			EMFTVMUtil.remove(env, eo, sf, value);
+			fail("Expected VMException");
+		} catch (IllegalArgumentException e) {
+			assertEquals("Cannot add/remove values of type Sequence to/from multi-valued field CodeBlock::code",
+					e.getMessage());
+		}
+	}
+
 }