Bug 551088 - DiagnosticCache throws NPE when deleting a reference

* Add Null check to AbstractCachedTree
* Handle external references in DiagnosticCache

Change-Id: If0345b264d216c2b8b4b6386142cace8fa5f6e6a
Signed-off-by: Eugen Neufeld <eneufeld@eclipsesource.com>
diff --git a/bundles/org.eclipse.emf.ecp.common/src/org/eclipse/emf/ecp/common/spi/cachetree/AbstractCachedTree.java b/bundles/org.eclipse.emf.ecp.common/src/org/eclipse/emf/ecp/common/spi/cachetree/AbstractCachedTree.java
index d02a4e0..c3d58f2 100644
--- a/bundles/org.eclipse.emf.ecp.common/src/org/eclipse/emf/ecp/common/spi/cachetree/AbstractCachedTree.java
+++ b/bundles/org.eclipse.emf.ecp.common/src/org/eclipse/emf/ecp/common/spi/cachetree/AbstractCachedTree.java
@@ -194,6 +194,9 @@
 		}
 
 		CachedTreeNode<T> node = nodes.get(eObject);
+		if (node == null) {
+			return;
+		}
 		final Object parentObject = node.getParent();
 		final CachedTreeNode<T> parentNode = parentObject == null ? null : nodes.get(parentObject);
 
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/diagnostic/DiagnosticCache.java b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/diagnostic/DiagnosticCache.java
index b185ab2..cecfc27 100644
--- a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/diagnostic/DiagnosticCache.java
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/diagnostic/DiagnosticCache.java
@@ -34,6 +34,7 @@
 import org.eclipse.emf.common.util.TreeIterator;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
 import org.eclipse.emf.ecore.EValidator;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
@@ -106,15 +107,28 @@
 		initializing = true;
 
 		try {
+			if (input == null) {
+				return;
+			}
 			this.input = input;
 			validationChangeListener = new ValidationChangeListener(input);
 			TreeIterator<Object> allContents;
+			final Set<EObject> externalReferences = new LinkedHashSet<EObject>();
 			if (ResourceSet.class.isInstance(input)) {
-				allContents = EcoreUtil.getAllContents(ResourceSet.class.cast(input), false);
+				final ResourceSet resourceSet = ResourceSet.class.cast(input);
+				allContents = EcoreUtil.getAllContents(resourceSet, false);
+				final Map<EObject, Collection<Setting>> map = EcoreUtil.ExternalCrossReferencer.find(resourceSet);
+				externalReferences.addAll(map.keySet());
 			} else if (Resource.class.isInstance(input)) {
-				allContents = EcoreUtil.getAllContents(Resource.class.cast(input), false);
+				final Resource resource = Resource.class.cast(input);
+				allContents = EcoreUtil.getAllContents(resource, false);
+				final Map<EObject, Collection<Setting>> map = EcoreUtil.ExternalCrossReferencer.find(resource);
+				externalReferences.addAll(map.keySet());
 			} else if (EObject.class.isInstance(input)) {
-				allContents = EcoreUtil.getAllContents(Collections.singleton(EObject.class.cast(input)), false);
+				final Set<EObject> set = Collections.singleton(EObject.class.cast(input));
+				allContents = EcoreUtil.getAllContents(set, false);
+				final Map<EObject, Collection<Setting>> map = EcoreUtil.ExternalCrossReferencer.find(set);
+				externalReferences.addAll(map.keySet());
 			} else {
 				return;
 			}
@@ -126,6 +140,7 @@
 				}
 				updateCacheWithoutRefresh(EObject.class.cast(next), this);
 			}
+			externalReferences.forEach(e -> updateCacheWithoutRefresh(e, this));
 		} finally {
 			initializing = wasInitializing;
 		}
diff --git a/tests/org.eclipse.emfforms.swt.treemasterdetail.test/src/org/eclipse/emfforms/swt/treemasterdetail/test/DiagnosticCache_Test.java b/tests/org.eclipse.emfforms.swt.treemasterdetail.test/src/org/eclipse/emfforms/swt/treemasterdetail/test/DiagnosticCache_Test.java
new file mode 100644
index 0000000..707e58e
--- /dev/null
+++ b/tests/org.eclipse.emfforms.swt.treemasterdetail.test/src/org/eclipse/emfforms/swt/treemasterdetail/test/DiagnosticCache_Test.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * eugen - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emfforms.swt.treemasterdetail.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emfforms.spi.swt.treemasterdetail.diagnostic.DiagnosticCache;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * DiagnosticCache Test.
+ *
+ * @author Eugen Neufeld
+ *
+ */
+public class DiagnosticCache_Test {
+
+	@Before
+	public void setUp() throws Exception {
+
+	}
+
+	@Test
+	public void testNull() {
+		final EObject object = null;
+		final DiagnosticCache cache = new DiagnosticCache(object);
+		assertEquals(0, cache.getObjects().size());
+	}
+
+	@Test
+	public void testExternalReferences() {
+		final EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
+
+		final DiagnosticCache cache = new DiagnosticCache(ePackage);
+		assertEquals(2, cache.getObjects().size());
+		assertTrue(cache.getObjects().contains(ePackage));
+		assertTrue(cache.getObjects().contains(ePackage.getEFactoryInstance()));
+	}
+
+	@Test
+	public void testNoExternalReferences() {
+		final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
+
+		final DiagnosticCache cache = new DiagnosticCache(eClass);
+		assertEquals(1, cache.getObjects().size());
+		assertTrue(cache.getObjects().contains(eClass));
+	}
+}