Bug 578725 - improve workspace.prepareOperation/endOperation pairs

if subMonitor.newChild throws a unchecked RuntimeException then the
"prepareOperation" would not be executed but "endOperation" which would
cause
IllegalArgumentException: endRule without matching beginRule

Change-Id: Iab9d828db8402cefedde29aff3fd08e5783d4e62
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.resources/+/190762
Tested-by: Andrey Loskutov <loskutov@gmx.de>
Reviewed-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
index 08480e7..8daa851 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
@@ -45,8 +45,9 @@
 			if (workspace.shouldValidate)
 				workspace.validateSave(this);
 			final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
+			SubMonitor newChild = subMonitor.newChild(1);
 			try {
-				workspace.prepareOperation(rule, subMonitor.newChild(1));
+				workspace.prepareOperation(rule, newChild);
 				ResourceInfo info = getResourceInfo(false, false);
 				checkAccessible(getFlags(info));
 				workspace.beginOperation(true);
@@ -102,8 +103,9 @@
 		try {
 			checkValidPath(path, FILE, true);
 			final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
+			SubMonitor newChild = subMonitor.newChild(1);
 			try {
-				workspace.prepareOperation(rule, subMonitor.newChild(1));
+				workspace.prepareOperation(rule, newChild);
 				checkDoesNotExist();
 				Container parent = (Container) getParent();
 				ResourceInfo info = parent.getResourceInfo(false, false);
@@ -327,8 +329,9 @@
 			if (workspace.shouldValidate)
 				workspace.validateSave(this);
 			final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
+			SubMonitor newChild = subMonitor.newChild(1);
 			try {
-				workspace.prepareOperation(rule, subMonitor.newChild(1));
+				workspace.prepareOperation(rule, newChild);
 				ResourceInfo info = getResourceInfo(false, false);
 				checkAccessible(getFlags(info));
 				workspace.beginOperation(true);
@@ -401,8 +404,9 @@
 		// need to get the project as a scheduling rule because we might be creating a new folder/file to
 		// hold the project settings
 		final ISchedulingRule rule = workspace.getRuleFactory().charsetRule(this);
+		SubMonitor newChild = subMonitor.newChild(1);
 		try {
-			workspace.prepareOperation(rule, subMonitor.newChild(1));
+			workspace.prepareOperation(rule, newChild);
 			ResourceInfo info = getResourceInfo(false, false);
 			checkAccessible(getFlags(info));
 			workspace.beginOperation(true);
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Folder.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Folder.java
index 3b4afd4..f2da547 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Folder.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Folder.java
@@ -86,8 +86,9 @@
 		SubMonitor subMonitor = SubMonitor.convert(monitor, message, 100);
 		checkValidPath(path, FOLDER, true);
 		final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
+		SubMonitor newChild = subMonitor.newChild(1);
 		try {
-			workspace.prepareOperation(rule, subMonitor.newChild(1));
+			workspace.prepareOperation(rule, newChild);
 			IFileStore store = getStore();
 			IFileInfo localInfo = store.fetchInfo();
 			assertCreateRequirements(store, localInfo, updateFlags);
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
index f907db7..ead6c1f 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
@@ -178,8 +178,9 @@
 		String msg = NLS.bind(Messages.resources_closing_1, getName());
 		SubMonitor subMonitor = SubMonitor.convert(monitor, msg, 100);
 		final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this);
+		SubMonitor newChild = subMonitor.newChild(1);
 		try {
-			workspace.prepareOperation(rule, subMonitor.newChild(1));
+			workspace.prepareOperation(rule, newChild);
 			ResourceInfo info = getResourceInfo(false, false);
 			int flags = getFlags(info);
 			checkExists(flags, true);
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
index 8b266e5..e72cc42 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
@@ -433,12 +433,13 @@
 		ISchedulingRule currentRule = null;
 		boolean buildParallel = noEnclosingRule && getDescription().getMaxConcurrentBuilds() > 1 && getDescription().getBuildOrder() == null;
 		SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+		SubMonitor newChild = subMonitor.newChild(1);
 		try {
 			try {
 
 				// Must run the PRE_BUILD with the WRule held before acquiring WS lock
 				// Can remove this if we run notifications without the WS lock held: bug 249951
-				prepareOperation(notificationRule, subMonitor.newChild(1));
+				prepareOperation(notificationRule, newChild);
 				currentRule = notificationRule;
 				beginOperation(true);
 				aboutToBuild(this, trigger);
@@ -609,18 +610,19 @@
 		//nothing to do if the workspace failed to open
 		if (!isOpen())
 			return;
+		String msg = Messages.resources_closing_0;
+		SubMonitor subMonitor = SubMonitor.convert(monitor, msg, 20);
+		subMonitor.subTask(msg);
+		// this operation will never end because the world is going away
+		SubMonitor newChild = subMonitor.newChild(1);
 		try {
-			String msg = Messages.resources_closing_0;
-			SubMonitor subMonitor = SubMonitor.convert(monitor, msg, 20);
-			subMonitor.subTask(msg);
-			//this operation will never end because the world is going away
 			try {
 				stringPoolJob.cancel();
 				//shutdown save manager now so a last snapshot can be taken before we close
 				//note: you can't call #save() from within a nested operation
 				saveManager.shutdown(null);
 				saveManager.reportSnapshotRequestor();
-				prepareOperation(getRoot(), subMonitor.newChild(1));
+				prepareOperation(getRoot(), newChild);
 				//shutdown notification first to avoid calling third parties during shutdown
 				notificationManager.shutdown(null);
 				beginOperation(true);