Bug 569286 - enhance NPE analysis in AbstractTextEditor

fTextEditor is null after disconnectEditor() for example due to
AbstractTextEditor.dispose. A disconnected Editor should not write
anything anymore.


Change-Id: I2d24a33b255c6c04c5dd8b27b900b1418ce30aec
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/182543
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
index 6ae6eb0..67ef523 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AbstractTextEditor.java
@@ -7099,6 +7099,10 @@
 		/** The cached document. */
 		private IDocument fDocument;
 
+		/** for debug only. see Bug 569286 **/
+		private Exception disconnectStack;
+		private boolean disconnectStackShown;
+
 		/**
 		 * Creates a new savable for this text editor.
 		 *
@@ -7116,7 +7120,12 @@
 		 */
 		public void disconnectEditor() {
 			getAdapter(IDocument.class); // make sure the document is cached
-			fTextEditor= null;
+			if (disconnectStack == null && !disconnectStackShown) {
+				disconnectStack = new IllegalStateException(
+						"Disconnected before saving. Please post stacktrace to https://bugs.eclipse.org/bugs/show_bug.cgi?id=569286 " //$NON-NLS-1$
+								+ fTextEditor.getClass().getName() + " " + getName()); //$NON-NLS-1$
+			}
+			fTextEditor = null;
 		}
 
 		@Override
@@ -7136,31 +7145,41 @@
 
 		@Override
 		public void doSave(IProgressMonitor monitor) throws CoreException {
-			try {
-				fTextEditor.doSave(monitor);
-			} catch (NullPointerException e) {
+			ITextEditor textEditor = fTextEditor;
+			if (textEditor == null) { // disconnected Editor - for example due to disposed
 				// This should not happen. Code added to handle the below bug.
-				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=550336
-				Bundle bundle = Platform.getBundle(PlatformUI.PLUGIN_ID);
-				ILog log = Platform.getLog(bundle);
-				Status status = new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, null, e);
-				log.log(status);
+				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=569286
+				if (disconnectStack != null && !disconnectStackShown) {
+					Bundle bundle = Platform.getBundle(PlatformUI.PLUGIN_ID);
+					ILog log = Platform.getLog(bundle);
+					disconnectStack.addSuppressed(new IllegalStateException("doSave after disconnect")); //$NON-NLS-1$
+					Status status = new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, null, disconnectStack);
+					log.log(status);
+					disconnectStackShown = true; // shut up
+				}
+				return;
 			}
+			textEditor.doSave(monitor);
 		}
 
 		@Override
 		public boolean isDirty() {
-			try {
-				return fTextEditor.isDirty();
-			} catch (NullPointerException e) {
+			ITextEditor textEditor = fTextEditor;
+			if (textEditor == null) { // disconnected Editor - for example due to disposed
 				// This should not happen. Code added to handle the below bug.
-				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=550336
-				Bundle bundle = Platform.getBundle(PlatformUI.PLUGIN_ID);
-				ILog log = Platform.getLog(bundle);
-				Status status = new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, null, e);
-				log.log(status);
+				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=569286
+				if (disconnectStack != null && !disconnectStackShown) {
+					Bundle bundle = Platform.getBundle(PlatformUI.PLUGIN_ID);
+					ILog log = Platform.getLog(bundle);
+					disconnectStack.addSuppressed(new IllegalStateException("isDirty check after disconnect")); //$NON-NLS-1$
+					Status status = new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, disconnectStack.getMessage(),
+							disconnectStack);
+					log.log(status);
+					disconnectStackShown = true; // shut up
+				}
 				return false;
 			}
+			return textEditor.isDirty();
 		}
 
 		/*