Bug 532572 - Undue reconcile delta on working copy creation for non-existing file
diff --git a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/ElementChangeRecorderTest.java b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/ElementChangeRecorderTest.java
index 9f04445..52d58a1 100644
--- a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/ElementChangeRecorderTest.java
+++ b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/ElementChangeRecorderTest.java
@@ -103,30 +103,25 @@
 
     public void test02()
     {
-        recorder.beginRecording(root);
-        rootBody.addChild(a);
-        //@formatter:off
-        assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
-            "  A[+]: {}", recorder.endRecording().getDelta().toString());
-        //@formatter:on
+        rootBody = null;
+        recorder.beginRecording(root, null, 0);
+        rootBody = new SourceElementBody();
+        assertEquals("root[+]: {}",
+            recorder.endRecording().getDelta().toString());
     }
 
     public void test03()
     {
-        rootBody.addChild(b);
-        recorder.beginRecording(root);
-        rootBody.addChild(a);
-        //@formatter:off
-        assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
-            "  A[+]: {}", recorder.endRecording().getDelta().toString());
-        //@formatter:on
+        recorder.beginRecording(root, null, 0);
+        rootBody = null;
+        assertEquals("root[-]: {}",
+            recorder.endRecording().getDelta().toString());
     }
 
     public void test04()
     {
-        rootBody.addChild(b);
         recorder.beginRecording(root);
-        rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
+        rootBody.addChild(a);
         //@formatter:off
         assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
             "  A[+]: {}", recorder.endRecording().getDelta().toString());
@@ -135,29 +130,29 @@
 
     public void test05()
     {
-        rootBody.addChild(a);
+        rootBody.addChild(b);
         recorder.beginRecording(root);
-        rootBody.removeChild(a);
+        rootBody.addChild(a);
         //@formatter:off
         assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
-            "  A[-]: {}", recorder.endRecording().getDelta().toString());
+            "  A[+]: {}", recorder.endRecording().getDelta().toString());
         //@formatter:on
     }
 
     public void test06()
     {
-        rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
+        rootBody.addChild(b);
         recorder.beginRecording(root);
-        rootBody.removeChild(a);
+        rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
         //@formatter:off
         assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
-            "  A[-]: {}", recorder.endRecording().getDelta().toString());
+            "  A[+]: {}", recorder.endRecording().getDelta().toString());
         //@formatter:on
     }
 
     public void test07()
     {
-        rootBody.setChildren(new SimpleSourceConstruct[] { b, a });
+        rootBody.addChild(a);
         recorder.beginRecording(root);
         rootBody.removeChild(a);
         //@formatter:off
@@ -170,6 +165,28 @@
     {
         rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
         recorder.beginRecording(root);
+        rootBody.removeChild(a);
+        //@formatter:off
+        assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
+            "  A[-]: {}", recorder.endRecording().getDelta().toString());
+        //@formatter:on
+    }
+
+    public void test09()
+    {
+        rootBody.setChildren(new SimpleSourceConstruct[] { b, a });
+        recorder.beginRecording(root);
+        rootBody.removeChild(a);
+        //@formatter:off
+        assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
+            "  A[-]: {}", recorder.endRecording().getDelta().toString());
+        //@formatter:on
+    }
+
+    public void test10()
+    {
+        rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
+        recorder.beginRecording(root);
         rootBody.setChildren(new SimpleSourceConstruct[] { b, a });
         //@formatter:off
         assertEquals("root[*]: {CHILDREN | FINE GRAINED}\n" +
@@ -179,7 +196,7 @@
         //@formatter:on
     }
 
-    public void test09()
+    public void test11()
     {
         rootBody.setFullRange(new TextRange(0, 0));
         recorder.beginRecording(root);
@@ -189,7 +206,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test10()
+    public void test12()
     {
         rootBody.setFullRange(new TextRange(0, 1));
         recorder.beginRecording(root);
@@ -199,7 +216,7 @@
             recorder.endRecording().getDelta()));
     }
 
-    public void test11()
+    public void test13()
     {
         rootBody.setFullRange(new TextRange(0, 1));
         Document document = new Document("a");
@@ -213,7 +230,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test12()
+    public void test14()
     {
         rootBody.setFullRange(new TextRange(0, 1));
         Document document = new Document("a");
@@ -226,26 +243,26 @@
             recorder.endRecording().getDelta()));
     }
 
-    public void test13()
-    {
-        recorder.beginRecording(root);
-        rootBody = new SourceElementBody();
-        rootBody.set(Property.get("p", String.class), "a");
-        assertEquals("root[*]: {CONTENT | FINE GRAINED}",
-            recorder.endRecording().getDelta().toString());
-    }
-
-    public void test14()
-    {
-        rootBody.set(Property.get("p", String.class), "a");
-        recorder.beginRecording(root);
-        rootBody = new SourceElementBody();
-        assertEquals("root[*]: {CONTENT | FINE GRAINED}",
-            recorder.endRecording().getDelta().toString());
-    }
-
     public void test15()
     {
+        recorder.beginRecording(root);
+        rootBody = new SourceElementBody();
+        rootBody.set(Property.get("p", String.class), "a");
+        assertEquals("root[*]: {CONTENT | FINE GRAINED}",
+            recorder.endRecording().getDelta().toString());
+    }
+
+    public void test16()
+    {
+        rootBody.set(Property.get("p", String.class), "a");
+        recorder.beginRecording(root);
+        rootBody = new SourceElementBody();
+        assertEquals("root[*]: {CONTENT | FINE GRAINED}",
+            recorder.endRecording().getDelta().toString());
+    }
+
+    public void test17()
+    {
         Property<String> p = Property.get("p", String.class);
         rootBody.set(p, "a");
         recorder.beginRecording(root);
@@ -255,7 +272,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test16()
+    public void test18()
     {
         Property<String[]> p = Property.get("p", String[].class);
         rootBody.set(p, new String[] { "a" });
@@ -266,7 +283,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test17()
+    public void test19()
     {
         rootBody.set(Property.get("p1", String.class), "a");
         recorder.beginRecording(root);
@@ -276,7 +293,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test18()
+    public void test20()
     {
         Property<String> p = Property.get("p", String.class);
         rootBody.set(p, "a");
@@ -287,14 +304,14 @@
             recorder.endRecording().getDelta()));
     }
 
-    public void test19()
+    public void test21()
     {
         recorder.beginRecording(root, null, 0);
         assertEquals("root[*]: {CONTENT}",
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test20()
+    public void test22()
     {
         rootBody = null;
         recorder.beginRecording(root, null, 0);
@@ -303,7 +320,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test21()
+    public void test23()
     {
         recorder.beginRecording(root, null, 0);
         rootBody = null;
@@ -311,7 +328,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test22()
+    public void test24()
     {
         rootBody.addChild(a);
         recorder.beginRecording(root, null, 0);
@@ -320,7 +337,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test23()
+    public void test25()
     {
         rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
         recorder.beginRecording(root, null, 0);
@@ -329,7 +346,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test24()
+    public void test26()
     {
         recorder.beginRecording(root, null, 0);
         rootBody = new SourceElementBody();
@@ -338,14 +355,14 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test25()
+    public void test27()
     {
         recorder.beginRecording(root, null, 1);
         assertTrue(ElementDeltas.isNullOrEmpty(
             recorder.endRecording().getDelta()));
     }
 
-    public void test26()
+    public void test28()
     {
         rootBody.addChild(a);
         recorder.beginRecording(root, null, 1);
@@ -357,7 +374,7 @@
         //@formatter:on
     }
 
-    public void test27()
+    public void test29()
     {
         rootBody.addChild(a);
         rootBody.addChild(b);
@@ -370,7 +387,7 @@
         //@formatter:on
     }
 
-    public void test28()
+    public void test30()
     {
         recorder.beginRecording(root, null, 1);
         rootBody = new SourceElementBody();
@@ -379,7 +396,7 @@
             recorder.endRecording().getDelta().toString());
     }
 
-    public void test29()
+    public void test31()
     {
         rootBody.addChild(a);
         recorder.beginRecording(root, null, 1);
@@ -391,7 +408,7 @@
         //@formatter:on
     }
 
-    public void test30()
+    public void test32()
     {
         rootBody.addChild(a);
         rootBody.addChild(b);
@@ -404,7 +421,7 @@
         //@formatter:on
     }
 
-    public void test31()
+    public void test33()
     {
         rootBody.addChild(a);
         rootBody.addChild(b);
@@ -417,7 +434,7 @@
         //@formatter:on
     }
 
-    public void test32()
+    public void test34()
     {
         rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
         recorder.beginRecording(root, null, 1);
@@ -432,7 +449,7 @@
         //@formatter:on
     }
 
-    public void test33()
+    public void test35()
     {
         rootBody.setChildren(new SimpleSourceConstruct[] { a, b });
         recorder.beginRecording(root, null, 2);
diff --git a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/OutOfSyncSourceFileTest.java b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/OutOfSyncSourceFileTest.java
index 69a19d4..45b82b4 100644
--- a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/OutOfSyncSourceFileTest.java
+++ b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/OutOfSyncSourceFileTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015, 2017 1C-Soft LLC.
+ * Copyright (c) 2015, 2018 1C-Soft LLC.
  * 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
@@ -50,7 +50,7 @@
         preferences.putBoolean(ResourcesPlugin.PREF_AUTO_REFRESH, false);
         preferences.putBoolean(ResourcesPlugin.PREF_LIGHTWEIGHT_AUTO_REFRESH,
             false);
-        file = setUpProject("Test001").getFile("file.txt");
+        file = setUpProject("Test001").getFile("a.foo");
         localFile = file.getLocation().toFile();
         sourceFile = new SimpleSourceFile(null, file.getName(), file,
             new SimpleModelManager());
diff --git a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/NullBodyCache.java b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleBodyCache.java
similarity index 73%
rename from org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/NullBodyCache.java
rename to org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleBodyCache.java
index 569c2ba..963848c 100644
--- a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/NullBodyCache.java
+++ b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleBodyCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 1C-Soft LLC.
+ * Copyright (c) 2018 1C-Soft LLC.
  * 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,33 +10,40 @@
  *******************************************************************************/
 package org.eclipse.handly.model.impl.support;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.eclipse.handly.model.IElement;
 
 /**
- * A null implementation of {@link IBodyCache} for tests.
+ * A simple body cache for tests.
  */
-class NullBodyCache
+public class SimpleBodyCache
     implements IBodyCache
 {
+    private Map<IElement, Object> map = new HashMap<>();
+
     @Override
     public Object get(IElement element)
     {
-        return null;
+        return map.get(element);
     }
 
     @Override
     public Object peek(IElement element)
     {
-        return null;
+        return map.get(element);
     }
 
     @Override
     public void put(IElement element, Object body)
     {
+        map.put(element, body);
     }
 
     @Override
     public void remove(IElement element)
     {
+        map.remove(element);
     }
 }
diff --git a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleModelManager.java b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleModelManager.java
index 78c0eec..ed08ff9 100644
--- a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleModelManager.java
+++ b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleModelManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 1C-Soft LLC.
+ * Copyright (c) 2017, 2018 1C-Soft LLC.
  * 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
@@ -18,9 +18,9 @@
 public class SimpleModelManager
     implements IModelManager
 {
-    public IModel model = new SimpleModel();
+    public SimpleModel model = new SimpleModel();
     public ElementManager elementManager = new ElementManager(
-        new NullBodyCache());
+        new SimpleBodyCache());
 
     @Override
     public IModel getModel()
diff --git a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleSourceFile.java b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleSourceFile.java
index ebe9b09..da57ea3 100644
--- a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleSourceFile.java
+++ b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/SimpleSourceFile.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015, 2017 1C-Soft LLC.
+ * Copyright (c) 2015, 2018 1C-Soft LLC.
  * 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
@@ -47,6 +47,18 @@
             throw new IllegalArgumentException();
     }
 
+    /**
+     * Returns a child element with the given name.
+     * This is a handle-only method.
+     *
+     * @param name the name of the element
+     * @return the child element with the given name
+     */
+    public SimpleSourceConstruct getChild(String name)
+    {
+        return new SimpleSourceConstruct(this, name);
+    }
+
     @Override
     public IModelManager getModelManager_()
     {
diff --git a/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/WorkingCopyNotificationTest.java b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/WorkingCopyNotificationTest.java
new file mode 100644
index 0000000..6102204
--- /dev/null
+++ b/org.eclipse.handly.tests/src/org/eclipse/handly/model/impl/support/WorkingCopyNotificationTest.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2018 1C-Soft LLC.
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Vladimir Piskarev (1C) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.handly.model.impl.support;
+
+import static org.eclipse.handly.context.Contexts.EMPTY_CONTEXT;
+import static org.eclipse.handly.context.Contexts.of;
+import static org.eclipse.handly.model.IElementChangeEvent.POST_CHANGE;
+import static org.eclipse.handly.model.IElementChangeEvent.POST_RECONCILE;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.handly.buffer.Buffer;
+import org.eclipse.handly.buffer.BufferChange;
+import org.eclipse.handly.buffer.IBuffer;
+import org.eclipse.handly.context.IContext;
+import org.eclipse.handly.junit.WorkspaceTestCase;
+import org.eclipse.handly.model.Elements;
+import org.eclipse.handly.model.IElementChangeEvent;
+import org.eclipse.handly.model.impl.ISourceFileImplExtension;
+import org.eclipse.text.edits.DeleteEdit;
+import org.eclipse.text.edits.InsertEdit;
+
+/**
+ * Working copy change notification tests.
+ */
+public class WorkingCopyNotificationTest
+    extends WorkspaceTestCase
+{
+    private SimpleSourceFile sourceFile;
+    private SimpleSourceConstruct aChild;
+    private List<IElementChangeEvent> events;
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        NotificationManager notificationManager = new NotificationManager();
+        notificationManager.addElementChangeListener((event) -> events.add(
+            event));
+        SimpleModelManager modelManager = new SimpleModelManager();
+        modelManager.model.context = of(INotificationManager.class,
+            notificationManager);
+        IFile file = setUpProject("Test001").getFile("a.foo");
+        sourceFile = new SimpleSourceFile(null, file.getName(), file,
+            modelManager)
+        {
+            @Override
+            public void buildSourceStructure_(IContext context,
+                IProgressMonitor monitor) throws CoreException
+            {
+                SourceElementBody body = new SourceElementBody();
+                if ("A".equals(context.get(SOURCE_CONTENTS)))
+                {
+                    body.addChild(aChild);
+
+                    context.get(NEW_ELEMENTS).put(aChild,
+                        new SourceElementBody());
+                }
+                context.get(NEW_ELEMENTS).put(this, body);
+            };
+        };
+        aChild = sourceFile.getChild("A");
+        events = new ArrayList<>();
+    }
+
+    public void test1() throws Exception
+    {
+        sourceFile.reconcile_(EMPTY_CONTEXT, null); // not a working copy
+        assertTrue(events.isEmpty()); // -> no effect
+    }
+
+    public void test2() throws Exception
+    {
+        sourceFile.becomeWorkingCopy_(EMPTY_CONTEXT, null);
+        try
+        {
+            assertEquals(1, events.size());
+            assertEvent(0, POST_CHANGE,
+                "[Working copy] a.foo[*]: {WORKING COPY}");
+
+            sourceFile.reconcile_(EMPTY_CONTEXT, null); // no changes
+            assertEquals(1, events.size()); // -> no effect
+
+            try (IBuffer buffer = sourceFile.getBuffer_(EMPTY_CONTEXT, null))
+            {
+                buffer.applyChange(new BufferChange(new InsertEdit(0, "A")),
+                    null);
+            }
+
+            sourceFile.reconcile_(EMPTY_CONTEXT, null);
+            assertEquals(2, events.size());
+            assertEvent(1, POST_RECONCILE,
+                "[Working copy] a.foo[*]: {CHILDREN | CONTENT | FINE GRAINED}\n"
+                    + "  A[+]: {}");
+        }
+        finally
+        {
+            sourceFile.releaseWorkingCopy_();
+        }
+        assertEquals(3, events.size());
+        assertEvent(2, POST_CHANGE, "a.foo[*]: {WORKING COPY}");
+    }
+
+    public void test3() throws Exception
+    {
+        sourceFile.becomeWorkingCopy_(of(
+            ISourceFileImplExtension.WORKING_COPY_BUFFER, new Buffer("A")),
+            null);
+        try
+        {
+            assertEquals(2, events.size());
+            assertEvent(0, POST_CHANGE,
+                "[Working copy] a.foo[*]: {WORKING COPY}");
+            assertEvent(1, POST_RECONCILE,
+                "[Working copy] a.foo[*]: {CHILDREN | CONTENT | FINE GRAINED}\n"
+                    + "  A[+]: {}");
+
+            sourceFile.reconcile_(of(Elements.FORCE_RECONCILING, true), null); // no changes
+            assertEquals(2, events.size()); // -> no effect
+
+            try (IBuffer buffer = sourceFile.getBuffer_(EMPTY_CONTEXT, null))
+            {
+                buffer.applyChange(new BufferChange(new DeleteEdit(0, 1)),
+                    null);
+            }
+
+            sourceFile.reconcile_(EMPTY_CONTEXT, null);
+            assertEquals(3, events.size());
+            assertEvent(2, POST_RECONCILE,
+                "[Working copy] a.foo[*]: {CHILDREN | CONTENT | FINE GRAINED}\n"
+                    + "  A[-]: {}");
+        }
+        finally
+        {
+            sourceFile.releaseWorkingCopy_();
+        }
+        assertEquals(4, events.size());
+        assertEvent(3, POST_CHANGE, "a.foo[*]: {WORKING COPY}");
+    }
+
+    public void test4() throws Exception
+    {
+        sourceFile.getFile_().delete(true, null);
+        sourceFile.becomeWorkingCopy_(EMPTY_CONTEXT, null);
+        try
+        {
+            assertEquals(1, events.size());
+            assertEvent(0, POST_CHANGE,
+                "[Working copy] a.foo[+]: {WORKING COPY}");
+        }
+        finally
+        {
+            sourceFile.releaseWorkingCopy_();
+        }
+        assertEquals(2, events.size());
+        assertEvent(1, POST_CHANGE, "a.foo[-]: {WORKING COPY}");
+    }
+
+    private void assertEvent(int index, int type, String expectedDelta)
+    {
+        IElementChangeEvent event = events.get(index);
+        assertEquals(type, event.getType());
+        assertEquals(expectedDelta, event.getDeltas()[0].toString());
+    }
+}
diff --git a/org.eclipse.handly.tests/workspace/Test001/file.txt b/org.eclipse.handly.tests/workspace/Test001/a.foo
old mode 100644
new mode 100755
similarity index 100%
rename from org.eclipse.handly.tests/workspace/Test001/file.txt
rename to org.eclipse.handly.tests/workspace/Test001/a.foo
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 88eef38..404998f 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
@@ -13,6 +13,7 @@
 import static org.eclipse.handly.context.Contexts.of;
 import static org.eclipse.handly.context.Contexts.with;
 import static org.eclipse.handly.model.Elements.CREATE_BUFFER;
+import static org.eclipse.handly.model.IElementDeltaConstants.CHANGED;
 import static org.eclipse.handly.model.IElementDeltaConstants.F_WORKING_COPY;
 import static org.eclipse.handly.util.ToStringOptions.FORMAT_STYLE;
 import static org.eclipse.handly.util.ToStringOptions.FormatStyle.MEDIUM;
@@ -899,7 +900,7 @@
                 reconcileStructure(context, monitor);
 
                 IElementDelta delta = recorder.endRecording().getDelta();
-                if (!ElementDeltas.isNullOrEmpty(delta))
+                if (delta != null && ElementDeltas.getKind(delta) == CHANGED)
                 {
                     Elements.getModelContext(sourceFile).get(
                         INotificationManager.class).fireElementChangeEvent(