Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Mayer2016-05-17 15:19:19 +0000
committerLaurent Delaigue2016-05-20 10:04:35 +0000
commitcc727ea40711b293accea0337cfc32272151cd36 (patch)
treeea92075836acef224e1984b4d90d745ae44bd92f
parent7517bb7436d01391643d96096946959f4e72bba4 (diff)
downloadorg.eclipse.emf.compare-cc727ea40711b293accea0337cfc32272151cd36.tar.gz
org.eclipse.emf.compare-cc727ea40711b293accea0337cfc32272151cd36.tar.xz
org.eclipse.emf.compare-cc727ea40711b293accea0337cfc32272151cd36.zip
[471045] Fix ArrayIndexOutOfBoundsException in model resolution
If we skip setValue() for particular features, then we also have to skip setManyReference() for them. Otherwise, setManyReference() may throw an ArrayIndexOutOfBoundsException by trying to insert values at invalid indexes (because expected values are missing) into many-valued features. This happenned when a non-containment EList had several elements with some of them resolved and others not yet resolved. Then, on endDocument(), the management of forward references invokes setManyReference(), expecting that elements already present are indeed present in the targeted EList, which is not the case with our parser pool. Bug: 471045 Change-Id: I09f014f3d3e59f7919aef091368d61de4e56a19a Signed-off-by: Andreas Mayer <anma-e@gmx.de> Signed-off-by: Laurent Delaigue <laurent.delaigue@obeo.fr>
-rw-r--r--plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/tests/suite/AllTests.java4
-rw-r--r--plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/Bug471045Test.java32
-rw-r--r--plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/data/bug471045.ecore18
-rw-r--r--plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/internal/utils/NotifyingParserPool.java36
4 files changed, 87 insertions, 3 deletions
diff --git a/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/tests/suite/AllTests.java
index 6885ce3e6..de4cc5ecb 100644
--- a/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/tests/suite/AllTests.java
@@ -14,6 +14,7 @@ import junit.framework.JUnit4TestAdapter;
import junit.framework.Test;
import junit.textui.TestRunner;
+import org.eclipse.emf.compare.ide.utils.tests.Bug471045Test;
import org.eclipse.emf.compare.ide.utils.tests.ResourceUtil_BinaryIdentical2Test;
import org.eclipse.emf.compare.ide.utils.tests.ResourceUtil_BinaryIdentical2_ReadLimitTest;
import org.eclipse.emf.compare.ide.utils.tests.ResourceUtil_BinaryIdentical3Test;
@@ -24,7 +25,8 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ResourceUtil_BinaryIdentical2Test.class, ResourceUtil_BinaryIdentical2_ReadLimitTest.class,
- ResourceUtil_BinaryIdentical3Test.class, ResourceUtil_BinaryIdentical3_ReadLimitTest.class })
+ ResourceUtil_BinaryIdentical3Test.class, ResourceUtil_BinaryIdentical3_ReadLimitTest.class,
+ Bug471045Test.class, })
public class AllTests {
/**
* Launches the test with the given arguments.
diff --git a/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/Bug471045Test.java b/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/Bug471045Test.java
new file mode 100644
index 000000000..989c1a35d
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/Bug471045Test.java
@@ -0,0 +1,32 @@
+package org.eclipse.emf.compare.ide.utils.tests;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.emf.compare.ide.internal.utils.NotifyingParserPool;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class Bug471045Test {
+
+ @Test
+ public void test() throws IOException {
+ InputStream stream = getClass().getResourceAsStream("data/bug471045.ecore"); //$NON-NLS-1$
+ try {
+ Resource r = new XMIResourceImpl();
+ NotifyingParserPool parserPool = new NotifyingParserPool(true);
+ Map<Object, Object> loadOptions = new HashMap<Object, Object>();
+ loadOptions.put(XMLResource.OPTION_USE_PARSER_POOL, parserPool);
+ r.load(stream, loadOptions);
+ // Prior to fix, this caused a BasicIndexOutOfBoundsException
+ } finally {
+ stream.close();
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/data/bug471045.ecore b/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/data/bug471045.ecore
new file mode 100644
index 000000000..1f5cda0c3
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.tests/src/org/eclipse/emf/compare/ide/utils/tests/data/bug471045.ecore
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="p" nsURI="p" nsPrefix="p">
+ <eClassifiers xsi:type="ecore:EClass" name="0"/>
+ <eClassifiers xsi:type="ecore:EClass" name="1" eSuperTypes="//@eClassifiers.0
+ //@eClassifiers.2
+ //@eClassifiers.3
+ //@eClassifiers.4
+ //@eClassifiers.5
+ //@eClassifiers.6
+ //@eClassifiers.7"/>
+ <eClassifiers xsi:type="ecore:EClass" name="2"/>
+ <eClassifiers xsi:type="ecore:EClass" name="3"/>
+ <eClassifiers xsi:type="ecore:EClass" name="4"/>
+ <eClassifiers xsi:type="ecore:EClass" name="5"/>
+ <eClassifiers xsi:type="ecore:EClass" name="6"/>
+ <eClassifiers xsi:type="ecore:EClass" name="7"/>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/internal/utils/NotifyingParserPool.java b/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/internal/utils/NotifyingParserPool.java
index 8b69eaa11..69b9559cb 100644
--- a/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/internal/utils/NotifyingParserPool.java
+++ b/plugins/org.eclipse.emf.compare.ide/src/org/eclipse/emf/compare/ide/internal/utils/NotifyingParserPool.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014, 2015 Obeo.
+ * Copyright (c) 2014, 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
@@ -10,9 +10,11 @@
*******************************************************************************/
package org.eclipse.emf.compare.ide.internal.utils;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
@@ -23,10 +25,12 @@ import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.ecore.xmi.XMIException;
import org.eclipse.emf.ecore.xmi.XMLDefaultHandler;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.XMLLoad;
import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.ecore.xmi.impl.XMLHandler;
import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -280,7 +284,6 @@ public class NotifyingParserPool extends XMLParserPoolImpl {
this.containmentOnly = containmentOnly;
}
- /** {@inheritDoc} */
@Override
public void setValue(EObject eObject, EStructuralFeature eStructuralFeature, Object value,
int position) {
@@ -299,6 +302,35 @@ public class NotifyingParserPool extends XMLParserPoolImpl {
}
}
+ /**
+ * Called by {@link XMLHandler} to set the values of the given many-valued forward reference. The
+ * target feature may already contain values resolved from backward references and set by
+ * {@link #setValue(EObject, EStructuralFeature, Object, int)}. The given reference also specifies the
+ * insertion indexes necessary to insert the new values at the correct positions.
+ * <p>
+ * Note that the super-implementation will throw an {@link ArrayIndexOutOfBoundsException} if the
+ * insertion indexes do not match the contents of the target feature, that is, if it contains too few
+ * elements.
+ *
+ * @param reference
+ * The reference to set
+ * @param location
+ * The location
+ * @return An empty list if the reference must be ignored, and the result of the parent implementation
+ * otherwise.
+ */
+ @Override
+ public List<XMIException> setManyReference(ManyReference reference, String location) {
+ EStructuralFeature eStructuralFeature = reference.getFeature();
+ boolean isContainment = eStructuralFeature instanceof EReference
+ && ((EReference)eStructuralFeature).isContainment();
+ if (!containmentOnly || isContainment) {
+ return super.setManyReference(reference, location);
+ }
+
+ return Collections.emptyList();
+ }
+
/** Check the {@link #potentialProxies} list for {@link EObject#eIsProxy() actual proxies}. */
public void checkProxies() {
Iterator<ProxyEntry> candidateIterator = potentialProxies.iterator();

Back to the top