Bug 528698 - Replace usage of SubProgressMonitor with SubMonitor
diff --git a/org.eclipse.handly.examples.basic.ui/src/org/eclipse/handly/internal/examples/basic/ui/model/FooProject.java b/org.eclipse.handly.examples.basic.ui/src/org/eclipse/handly/internal/examples/basic/ui/model/FooProject.java
index 819c0b7..c65081a 100644
--- a/org.eclipse.handly.examples.basic.ui/src/org/eclipse/handly/internal/examples/basic/ui/model/FooProject.java
+++ b/org.eclipse.handly.examples.basic.ui/src/org/eclipse/handly/internal/examples/basic/ui/model/FooProject.java
@@ -22,8 +22,7 @@
 import org.eclipse.core.resources.IWorkspaceRunnable;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.context.IContext;
 import org.eclipse.handly.examples.basic.ui.model.IFooFile;
 import org.eclipse.handly.examples.basic.ui.model.IFooProject;
@@ -63,41 +62,30 @@
     }
 
     @Override
-    public void create(final URI location, IProgressMonitor monitor)
+    public void create(URI location, IProgressMonitor monitor)
         throws CoreException
     {
-        final IWorkspace workspace = getParent().getWorkspace();
+        IWorkspace workspace = getParent().getWorkspace();
         workspace.run(new IWorkspaceRunnable()
         {
             @Override
             public void run(IProgressMonitor monitor) throws CoreException
             {
-                if (monitor == null)
-                    monitor = new NullProgressMonitor();
-                try
-                {
-                    monitor.beginTask("", 4); //$NON-NLS-1$
+                SubMonitor subMonitor = SubMonitor.convert(monitor, 4);
 
-                    IProjectDescription description =
-                        workspace.newProjectDescription(getName());
-                    description.setLocationURI(location);
-                    project.create(description, new SubProgressMonitor(monitor,
-                        1));
-                    project.open(new SubProgressMonitor(monitor, 1));
+                IProjectDescription description =
+                    workspace.newProjectDescription(getName());
+                description.setLocationURI(location);
+                project.create(description, subMonitor.split(1));
+                project.open(subMonitor.split(1));
 
-                    description.setNatureIds(new String[] {
-                        "org.eclipse.xtext.ui.shared.xtextNature", //$NON-NLS-1$
-                        IFooProject.NATURE_ID });
-                    project.setDescription(description, new SubProgressMonitor(
-                        monitor, 1));
+                description.setNatureIds(new String[] {
+                    "org.eclipse.xtext.ui.shared.xtextNature", //$NON-NLS-1$
+                    IFooProject.NATURE_ID });
+                project.setDescription(description, subMonitor.split(1));
 
-                    project.setDefaultCharset("UTF-8", //$NON-NLS-1$
-                        new SubProgressMonitor(monitor, 1));
-                }
-                finally
-                {
-                    monitor.done();
-                }
+                project.setDefaultCharset("UTF-8", //$NON-NLS-1$
+                    subMonitor.split(1));
             }
         }, monitor);
     }
diff --git a/org.eclipse.handly.examples.jmodel/src/org/eclipse/handly/internal/examples/jmodel/Type.java b/org.eclipse.handly.examples.jmodel/src/org/eclipse/handly/internal/examples/jmodel/Type.java
index e8788d1..c1c37d5 100644
--- a/org.eclipse.handly.examples.jmodel/src/org/eclipse/handly/internal/examples/jmodel/Type.java
+++ b/org.eclipse.handly.examples.jmodel/src/org/eclipse/handly/internal/examples/jmodel/Type.java
@@ -18,8 +18,7 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.context.IContext;
 import org.eclipse.handly.examples.jmodel.IField;
 import org.eclipse.handly.examples.jmodel.IMember;
@@ -153,64 +152,54 @@
                 context = with(of(BASE_SNAPSHOT, snapshot), context);
         }
         ISourceElement[] children = info.getChildren();
-        monitor.beginTask("", children.length);
-        try
+        SubMonitor loopMonitor = SubMonitor.convert(monitor, children.length);
+        for (int i = children.length - 1; i >= 0; i--)
         {
-            for (int i = children.length - 1; i >= 0; i--)
+            SubMonitor iterationMonitor = loopMonitor.split(1);
+            ISourceElement child = children[i];
+            if (child instanceof IField)
             {
-                if (monitor.isCanceled())
-                    throw new OperationCanceledException();
-                ISourceElement child = children[i];
-                if (child instanceof IField)
+                ISourceElementInfo childInfo = Elements.getSourceElementInfo(
+                    child);
+                if (ISourceElementImplSupport.checkInRange(position, childInfo,
+                    context))
                 {
-                    ISourceElementInfo childInfo =
-                        Elements.getSourceElementInfo(child);
-                    if (ISourceElementImplSupport.checkInRange(position,
-                        childInfo, context))
+                    // check multi-declaration case (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=465410)
+                    ISourceElement candidate = null;
+                    do
                     {
-                        // check multi-declaration case (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=465410)
-                        ISourceElement candidate = null;
-                        do
-                        {
-                            // check name range
-                            TextRange nameRange =
-                                childInfo.getIdentifyingRange();
-                            if (nameRange != null
-                                && position <= nameRange.getEndOffset())
-                                candidate = child;
-                            else
-                                return candidate == null ? child : candidate;
+                        // check name range
+                        TextRange nameRange = childInfo.getIdentifyingRange();
+                        if (nameRange != null
+                            && position <= nameRange.getEndOffset())
+                            candidate = child;
+                        else
+                            return candidate == null ? child : candidate;
 
-                            if (--i < 0)
-                                child = null;
-                            else
-                            {
-                                child = children[i];
-                                childInfo = Elements.getSourceElementInfo(
-                                    child);
-                            }
+                        if (--i < 0)
+                            child = null;
+                        else
+                        {
+                            child = children[i];
+                            childInfo = Elements.getSourceElementInfo(child);
                         }
-                        while (child != null
-                            && ISourceElementImplSupport.checkInRange(position,
-                                childInfo, context));
-                        // position in field's type: use first field
-                        return candidate;
                     }
-                }
-                else
-                {
-                    ISourceElement found = Elements.getSourceElementAt(child,
-                        position, context, new SubProgressMonitor(monitor, 1));
-                    if (found != null)
-                        return found;
+                    while (child != null
+                        && ISourceElementImplSupport.checkInRange(position,
+                            childInfo, context));
+                    // position in field's type: use first field
+                    return candidate;
                 }
             }
-            return this;
+            else
+            {
+                ISourceElement found = Elements.getSourceElementAt(child,
+                    position, context, iterationMonitor);
+                if (found != null)
+                    return found;
+            }
         }
-        finally
-        {
-            monitor.done();
-        }
+        return this;
     }
 
     @Override
diff --git a/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/editor/HandlyXtextDocument.java b/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/editor/HandlyXtextDocument.java
index aaecb69..8045982 100644
--- a/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/editor/HandlyXtextDocument.java
+++ b/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/editor/HandlyXtextDocument.java
@@ -16,7 +16,7 @@
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.SafeRunner;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.emf.common.util.WrappedException;
 import org.eclipse.handly.internal.xtext.ui.Activator;
 import org.eclipse.handly.snapshot.DocumentSnapshot;
@@ -271,41 +271,28 @@
      * @param monitor a progress monitor (never <code>null</code>)
      * @throws OperationCanceledException if this method is canceled
      */
-    private void reconciled(final XtextResource resource,
-        final NonExpiringSnapshot snapshot, final boolean forced,
-        final IProgressMonitor monitor)
+    private void reconciled(XtextResource resource,
+        NonExpiringSnapshot snapshot, boolean forced, IProgressMonitor monitor)
     {
         Object[] listeners = reconcilingListeners.getListeners();
-        monitor.beginTask("", listeners.length); //$NON-NLS-1$
-        try
+        SubMonitor loopMonitor = SubMonitor.convert(monitor, listeners.length);
+        for (Object listener : listeners)
         {
-            for (final Object listener : listeners)
+            SubMonitor iterationMonitor = loopMonitor.split(1);
+            SafeRunner.run(new ISafeRunnable()
             {
-                if (monitor.isCanceled())
-                    break;
-
-                SafeRunner.run(new ISafeRunnable()
+                @Override
+                public void run() throws Exception
                 {
-                    @Override
-                    public void run() throws Exception
-                    {
-                        ((IReconcilingListener)listener).reconciled(resource,
-                            snapshot, forced, new SubProgressMonitor(monitor,
-                                1));
-                    }
+                    ((IReconcilingListener)listener).reconciled(resource,
+                        snapshot, forced, iterationMonitor);
+                }
 
-                    @Override
-                    public void handleException(Throwable exception)
-                    {
-                    }
-                });
-            }
-            if (monitor.isCanceled())
-                throw new OperationCanceledException();
-        }
-        finally
-        {
-            monitor.done();
+                @Override
+                public void handleException(Throwable exception)
+                {
+                }
+            });
         }
     }
 
@@ -428,94 +415,41 @@
          * makes a note that reconciling was canceled and returns.
          */
         @Override
-        public Boolean exec(final XtextResource resource) throws Exception
+        public Boolean exec(XtextResource resource) throws Exception
         {
-            final IProgressMonitor monitor = getReconcilingMonitor();
-            monitor.beginTask("", 2); //$NON-NLS-1$
-            try
+            SubMonitor subMonitor = SubMonitor.convert(getReconcilingMonitor(),
+                2);
+
+            if (resource == null) // input not set or already disposed
             {
-                if (resource == null) // input not set or already disposed
-                {
-                    if (force)
-                        throw new NoXtextResourceException(
-                            HandlyXtextDocument.this);
-                    return false;
-                }
+                if (force)
+                    throw new NoXtextResourceException(
+                        HandlyXtextDocument.this);
+                return false;
+            }
 
-                if (monitor.isCanceled())
-                {
-                    reconcilingWasCanceled = true;
-                    return false;
-                }
+            if (subMonitor.isCanceled())
+            {
+                reconcilingWasCanceled = true;
+                return false;
+            }
 
-                PendingChange change = getAndResetPendingChange();
-                if (change == null)
+            PendingChange change = getAndResetPendingChange();
+            if (change == null)
+            {
+                if (force || reconcilingWasCanceled)
                 {
-                    if (force || reconcilingWasCanceled)
-                    {
-                        final NonExpiringSnapshot snapshot = reconciledSnapshot;
-                        if (force) // no need to reparse -- just update internal state
-                            resource.update(0, 0, ""); //$NON-NLS-1$
-                        SafeRunner.run(new ISafeRunnable()
-                        {
-                            @Override
-                            public void run() throws Exception
-                            {
-                                reconciled(resource, snapshot,
-                                    !reconcilingWasCanceled,
-                                    new SubProgressMonitor(monitor, 2));
-                            }
-
-                            @Override
-                            public void handleException(Throwable exception)
-                            {
-                                // the exception is suppressed, including OCE
-                            }
-                        });
-                        reconcilingWasCanceled = monitor.isCanceled();
-                    }
-                    return false;
-                }
-                else
-                {
-                    final NonExpiringSnapshot snapshot =
-                        change.getSnapshotToReconcile();
-                    ReplaceRegion replaceRegion =
-                        change.getReplaceRegionToReconcile();
-                    long modificationStamp = change.getModificationStamp();
-                    try
-                    {
-                        resource.update(replaceRegion.getOffset(),
-                            replaceRegion.getLength(), replaceRegion.getText());
-                        resource.setModificationStamp(modificationStamp);
-                    }
-                    catch (Exception e)
-                    {
-                        // partial parsing failed - performing full reparse
-                        Activator.log(Activator.createErrorStatus(
-                            e.getMessage(), e));
-                        try
-                        {
-                            resource.reparse(snapshot.getContents());
-                            resource.setModificationStamp(modificationStamp);
-                        }
-                        catch (Exception e2)
-                        {
-                            // full parsing also failed - restore state
-                            Activator.log(Activator.createErrorStatus(
-                                e2.getMessage(), e2));
-                            resource.reparse(reconciledSnapshot.getContents());
-                            throw e2;
-                        }
-                    }
+                    NonExpiringSnapshot snapshot = reconciledSnapshot;
+                    if (force) // no need to reparse -- just update internal state
+                        resource.update(0, 0, ""); //$NON-NLS-1$
                     SafeRunner.run(new ISafeRunnable()
                     {
                         @Override
                         public void run() throws Exception
                         {
-                            monitor.worked(1);
-                            reconciled(resource, snapshot, false,
-                                new SubProgressMonitor(monitor, 1));
+                            subMonitor.worked(1);
+                            reconciled(resource, snapshot,
+                                !reconcilingWasCanceled, subMonitor.split(1));
                         }
 
                         @Override
@@ -524,14 +458,60 @@
                             // the exception is suppressed, including OCE
                         }
                     });
-                    reconcilingWasCanceled = monitor.isCanceled();
-                    reconciledSnapshot = snapshot;
-                    return true;
+                    reconcilingWasCanceled = subMonitor.isCanceled();
                 }
+                return false;
             }
-            finally
+            else
             {
-                monitor.done();
+                NonExpiringSnapshot snapshot = change.getSnapshotToReconcile();
+                ReplaceRegion replaceRegion =
+                    change.getReplaceRegionToReconcile();
+                long modificationStamp = change.getModificationStamp();
+                try
+                {
+                    resource.update(replaceRegion.getOffset(),
+                        replaceRegion.getLength(), replaceRegion.getText());
+                    resource.setModificationStamp(modificationStamp);
+                }
+                catch (Exception e)
+                {
+                    // partial parsing failed - performing full reparse
+                    Activator.log(Activator.createErrorStatus(e.getMessage(),
+                        e));
+                    try
+                    {
+                        resource.reparse(snapshot.getContents());
+                        resource.setModificationStamp(modificationStamp);
+                    }
+                    catch (Exception e2)
+                    {
+                        // full parsing also failed - restore state
+                        Activator.log(Activator.createErrorStatus(
+                            e2.getMessage(), e2));
+                        resource.reparse(reconciledSnapshot.getContents());
+                        throw e2;
+                    }
+                }
+                SafeRunner.run(new ISafeRunnable()
+                {
+                    @Override
+                    public void run() throws Exception
+                    {
+                        subMonitor.worked(1);
+                        reconciled(resource, snapshot, false, subMonitor.split(
+                            1));
+                    }
+
+                    @Override
+                    public void handleException(Throwable exception)
+                    {
+                        // the exception is suppressed, including OCE
+                    }
+                });
+                reconcilingWasCanceled = subMonitor.isCanceled();
+                reconciledSnapshot = snapshot;
+                return true;
             }
         }
     }
@@ -653,7 +633,7 @@
         @Override
         public void reconciled(XtextResource resource,
             NonExpiringSnapshot snapshot, boolean forced,
-            final IProgressMonitor monitor) throws Exception
+            IProgressMonitor monitor) throws Exception
         {
             CancelIndicator cancelIndicator = new CancelIndicator()
             {
@@ -663,7 +643,6 @@
                     return monitor.isCanceled();
                 }
             };
-            monitor.beginTask("", 1); //$NON-NLS-1$
             try
             {
                 EcoreUtil2.resolveLazyCrossReferences(resource,
@@ -680,10 +659,6 @@
                 if (!(t instanceof OperationCanceledError))
                     Throwables.propagate(t);
             }
-            finally
-            {
-                monitor.done();
-            }
         }
     }
 }
diff --git a/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/IElementImplSupport.java b/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/IElementImplSupport.java
index 0a1549e..3b44182 100644
--- a/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/IElementImplSupport.java
+++ b/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/IElementImplSupport.java
@@ -28,9 +28,8 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.context.IContext;
 import org.eclipse.handly.internal.Activator;
 import org.eclipse.handly.model.Elements;
@@ -221,69 +220,56 @@
     default Object open_(IContext context, IProgressMonitor monitor)
         throws CoreException
     {
-        if (monitor == null)
-            monitor = new NullProgressMonitor();
-        monitor.beginTask("", 2); //$NON-NLS-1$
-        try
-        {
-            openParent_(!Boolean.TRUE.equals(context.get(FORCE_OPEN)) ? context
-                : with(of(FORCE_OPEN, false), context), new SubProgressMonitor(
-                    monitor, 1));
+        SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
 
-            Object body;
-            if (!isOpenable_())
+        openParent_(!Boolean.TRUE.equals(context.get(FORCE_OPEN)) ? context
+            : with(of(FORCE_OPEN, false), context), subMonitor.split(1));
+
+        Object body;
+        if (!isOpenable_())
+        {
+            body = findBody_();
+            if (body == null)
+                throw newDoesNotExistException_();
+        }
+        else
+        {
+            validateExistence_(context);
+
+            ElementManager elementManager = getElementManager_();
+
+            Map<IElement, Object> newElements = new HashMap<IElement, Object>();
+
+            elementManager.pushTemporaryCache(newElements);
+            try
             {
-                body = findBody_();
-                if (body == null)
-                    throw newDoesNotExistException_();
+                buildStructure_(with(of(NEW_ELEMENTS, newElements), context),
+                    subMonitor.split(1));
             }
+            finally
+            {
+                elementManager.popTemporaryCache();
+            }
+
+            body = newElements.get(this);
+            if (body == null)
+            {
+                throw new AssertionError(MessageFormat.format(
+                    "No body for {0}. Incorrect {1}#buildStructure_ implementation?", //$NON-NLS-1$
+                    toString(), getClass().getSimpleName()));
+            }
+
+            if (context.getOrDefault(FORCE_OPEN))
+                elementManager.put(this, newElements);
             else
             {
-                validateExistence_(context);
-
-                if (monitor.isCanceled())
-                    throw new OperationCanceledException();
-
-                ElementManager elementManager = getElementManager_();
-
-                Map<IElement, Object> newElements =
-                    new HashMap<IElement, Object>();
-
-                elementManager.pushTemporaryCache(newElements);
-                try
-                {
-                    buildStructure_(with(of(NEW_ELEMENTS, newElements),
-                        context), new SubProgressMonitor(monitor, 1));
-                }
-                finally
-                {
-                    elementManager.popTemporaryCache();
-                }
-
-                body = newElements.get(this);
-                if (body == null)
-                {
-                    throw new AssertionError(MessageFormat.format(
-                        "No body for {0}. Incorrect {1}#buildStructure_ implementation?", //$NON-NLS-1$
-                        toString(), getClass().getSimpleName()));
-                }
-
-                if (context.getOrDefault(FORCE_OPEN))
-                    elementManager.put(this, newElements);
-                else
-                {
-                    Object existingBody = elementManager.putIfAbsent(this,
-                        newElements);
-                    if (existingBody != null)
-                        body = existingBody;
-                }
+                Object existingBody = elementManager.putIfAbsent(this,
+                    newElements);
+                if (existingBody != null)
+                    body = existingBody;
             }
-            return body;
         }
-        finally
-        {
-            monitor.done();
-        }
+        return body;
     }
 
     /**
diff --git a/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceElementImplSupport.java b/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceElementImplSupport.java
index d7529e0..3a62fd3 100644
--- a/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceElementImplSupport.java
+++ b/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceElementImplSupport.java
@@ -16,9 +16,7 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.context.IContext;
 import org.eclipse.handly.model.Elements;
 import org.eclipse.handly.model.ISourceElement;
@@ -63,22 +61,13 @@
     default ISourceElement getSourceElementAt_(int position, IContext context,
         IProgressMonitor monitor) throws CoreException
     {
-        if (monitor == null)
-            monitor = new NullProgressMonitor();
-        monitor.beginTask("", 2); //$NON-NLS-1$
-        try
-        {
-            ISourceElementInfo info = getSourceElementInfo_(context,
-                new SubProgressMonitor(monitor, 1));
-            if (!checkInRange(position, info, context))
-                return null;
-            return getSourceElementAt_(position, info, context,
-                new SubProgressMonitor(monitor, 1));
-        }
-        finally
-        {
-            monitor.done();
-        }
+        SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
+        ISourceElementInfo info = getSourceElementInfo_(context,
+            subMonitor.split(1));
+        if (!checkInRange(position, info, context))
+            return null;
+        return getSourceElementAt_(position, info, context, subMonitor.split(
+            1));
     }
 
     /**
@@ -108,24 +97,16 @@
                 context = with(of(BASE_SNAPSHOT, snapshot), context);
         }
         ISourceElement[] children = info.getChildren();
-        monitor.beginTask("", children.length); //$NON-NLS-1$
-        try
+        SubMonitor loopMonitor = SubMonitor.convert(monitor, children.length);
+        for (ISourceElement child : children)
         {
-            for (ISourceElement child : children)
-            {
-                if (monitor.isCanceled())
-                    throw new OperationCanceledException();
-                ISourceElement found = Elements.getSourceElementAt(child,
-                    position, context, new SubProgressMonitor(monitor, 1));
-                if (found != null)
-                    return found;
-            }
-            return this;
+            SubMonitor iterationMonitor = loopMonitor.split(1);
+            ISourceElement found = Elements.getSourceElementAt(child, position,
+                context, iterationMonitor);
+            if (found != null)
+                return found;
         }
-        finally
-        {
-            monitor.done();
-        }
+        return this;
     }
 
     /**
diff --git a/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceFileImplSupport.java b/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceFileImplSupport.java
index b24c5af..3fde46f 100644
--- a/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceFileImplSupport.java
+++ b/org.eclipse.handly/src/org/eclipse/handly/model/impl/support/ISourceFileImplSupport.java
@@ -26,9 +26,8 @@
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.buffer.IBuffer;
 import org.eclipse.handly.buffer.ICoreTextFileBufferProvider;
 import org.eclipse.handly.buffer.TextFileBuffer;
@@ -105,41 +104,30 @@
     default IBuffer getBuffer_(IContext context, IProgressMonitor monitor)
         throws CoreException
     {
-        if (monitor == null)
-            monitor = new NullProgressMonitor();
-        monitor.beginTask("", 100); //$NON-NLS-1$
-        try
+        SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+        if (!acquireExistingWorkingCopy_(subMonitor.split(10)))
         {
-            if (!acquireExistingWorkingCopy_(new SubProgressMonitor(monitor,
-                10)))
-            {
-                return getFileBuffer_(context, new SubProgressMonitor(monitor,
-                    90));
-            }
-            else
-            {
-                try
-                {
-                    WorkingCopyInfo info =
-                        getElementManager_().peekAtWorkingCopyInfo(this);
-
-                    if (info == null)
-                        throw new AssertionError(
-                            "This method probably needs to be overridden"); //$NON-NLS-1$
-
-                    IBuffer buffer = info.getBuffer();
-                    buffer.addRef();
-                    return buffer;
-                }
-                finally
-                {
-                    releaseWorkingCopy_();
-                }
-            }
+            return getFileBuffer_(context, subMonitor.split(90));
         }
-        finally
+        else
         {
-            monitor.done();
+            try
+            {
+                WorkingCopyInfo info =
+                    getElementManager_().peekAtWorkingCopyInfo(this);
+
+                if (info == null)
+                    throw new AssertionError(
+                        "This method probably needs to be overridden"); //$NON-NLS-1$
+
+                IBuffer buffer = info.getBuffer();
+                buffer.addRef();
+                return buffer;
+            }
+            finally
+            {
+                releaseWorkingCopy_();
+            }
         }
     }
 
@@ -240,37 +228,26 @@
     default void reconcile_(IContext context, IProgressMonitor monitor)
         throws CoreException
     {
-        if (monitor == null)
-            monitor = new NullProgressMonitor();
-        monitor.beginTask("", 100); //$NON-NLS-1$
-        try
+        SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+        if (!acquireExistingWorkingCopy_(subMonitor.split(10)))
+            return; // not a working copy
+        else
         {
-            if (!acquireExistingWorkingCopy_(new SubProgressMonitor(monitor,
-                10)))
-                return; // not a working copy
-            else
+            try
             {
-                try
-                {
-                    WorkingCopyInfo info =
-                        getElementManager_().peekAtWorkingCopyInfo(this);
+                WorkingCopyInfo info =
+                    getElementManager_().peekAtWorkingCopyInfo(this);
 
-                    if (info == null)
-                        throw new AssertionError(
-                            "This method probably needs to be overriden"); //$NON-NLS-1$
+                if (info == null)
+                    throw new AssertionError(
+                        "This method probably needs to be overriden"); //$NON-NLS-1$
 
-                    info.callback.reconcile(context, new SubProgressMonitor(
-                        monitor, 90));
-                }
-                finally
-                {
-                    releaseWorkingCopy_();
-                }
+                info.callback.reconcile(context, subMonitor.split(90));
             }
-        }
-        finally
-        {
-            monitor.done();
+            finally
+            {
+                releaseWorkingCopy_();
+            }
         }
     }
 
diff --git a/org.eclipse.handly/src/org/eclipse/handly/refactoring/SourceFileChange.java b/org.eclipse.handly/src/org/eclipse/handly/refactoring/SourceFileChange.java
index d6f4fa4..8614b49 100644
--- a/org.eclipse.handly/src/org/eclipse/handly/refactoring/SourceFileChange.java
+++ b/org.eclipse.handly/src/org/eclipse/handly/refactoring/SourceFileChange.java
@@ -29,7 +29,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.buffer.BufferChange;
 import org.eclipse.handly.buffer.IBuffer;
 import org.eclipse.handly.buffer.IBufferChange;
@@ -247,10 +247,10 @@
     @Override
     public Change perform(IProgressMonitor pm) throws CoreException
     {
-        pm.beginTask("", 2); //$NON-NLS-1$
+        SubMonitor subMonitor = SubMonitor.convert(pm, 2);
         try (
             IBuffer buffer = getBuffer(sourceFile, EMPTY_CONTEXT,
-                new SubProgressMonitor(pm, 1)))
+                subMonitor.split(1)))
         {
             BufferChangeWithExcludes change = new BufferChangeWithExcludes(
                 edit);
@@ -264,8 +264,9 @@
 
             try
             {
-                undoChange = buffer.applyChange(change, new SubProgressMonitor(
-                    pm, 1));
+                undoChange = buffer.applyChange(change, subMonitor.split(1,
+                    SubMonitor.SUPPRESS_ISCANCELED
+                        | SubMonitor.SUPPRESS_BEGINTASK));
             }
             catch (StaleSnapshotException e)
             {
@@ -277,10 +278,6 @@
 
             return new UndoSourceFileChange(getName(), sourceFile, undoChange);
         }
-        finally
-        {
-            pm.done();
-        }
     }
 
     @Override
diff --git a/org.eclipse.handly/src/org/eclipse/handly/refactoring/UndoSourceFileChange.java b/org.eclipse.handly/src/org/eclipse/handly/refactoring/UndoSourceFileChange.java
index ff3e0a3..0c4af01 100644
--- a/org.eclipse.handly/src/org/eclipse/handly/refactoring/UndoSourceFileChange.java
+++ b/org.eclipse.handly/src/org/eclipse/handly/refactoring/UndoSourceFileChange.java
@@ -22,7 +22,7 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.handly.buffer.IBuffer;
 import org.eclipse.handly.buffer.IBufferChange;
 import org.eclipse.handly.internal.Activator;
@@ -104,17 +104,18 @@
     @Override
     public Change perform(IProgressMonitor pm) throws CoreException
     {
-        pm.beginTask("", 2); //$NON-NLS-1$
+        SubMonitor subMonitor = SubMonitor.convert(pm, 2);
         try (
             IBuffer buffer = getBuffer(sourceFile, EMPTY_CONTEXT,
-                new SubProgressMonitor(pm, 1)))
+                subMonitor.split(1)))
         {
             IBufferChange redoChange;
 
             try
             {
-                redoChange = buffer.applyChange(undoChange,
-                    new SubProgressMonitor(pm, 1));
+                redoChange = buffer.applyChange(undoChange, subMonitor.split(1,
+                    SubMonitor.SUPPRESS_ISCANCELED
+                        | SubMonitor.SUPPRESS_BEGINTASK));
             }
             catch (StaleSnapshotException e)
             {
@@ -126,10 +127,6 @@
 
             return new UndoSourceFileChange(getName(), sourceFile, redoChange);
         }
-        finally
-        {
-            pm.done();
-        }
     }
 
     @Override