Makes SplittableList.remove() to behave correctly.

Before this patch, SplittableList.remove() has assigned "null" as
reified value for any index that has not yet been reified and that is
larger than the index to be removed.
For these indexes SplittableList.get(int) has then returned "null"
even though a value exists in the Splittable.

Bug: issue 8854
Change-Id: Ie6f2c7b66926d4a09c4797be870bf4efcc7dfe02
diff --git a/user/src/com/google/web/bindery/autobean/gwt/client/impl/JsoSplittable.java b/user/src/com/google/web/bindery/autobean/gwt/client/impl/JsoSplittable.java
index 36a2677..ed15270 100644
--- a/user/src/com/google/web/bindery/autobean/gwt/client/impl/JsoSplittable.java
+++ b/user/src/com/google/web/bindery/autobean/gwt/client/impl/JsoSplittable.java
@@ -210,6 +210,13 @@
     return this[key] === undefined;
   }-*/;
 
+  @Override
+  public native void removeReified(String key) /*-{
+    if (this.__reified) {
+      delete this.__reified[':' + key];
+    }
+  }-*/;
+
   public native void setReified(String key, Object object) /*-{
     // Use a function object so native JSON.stringify will ignore
     (this.__reified || (this.__reified = function() {
diff --git a/user/src/com/google/web/bindery/autobean/shared/Splittable.java b/user/src/com/google/web/bindery/autobean/shared/Splittable.java
index 2fc1cba..95fe557 100644
--- a/user/src/com/google/web/bindery/autobean/shared/Splittable.java
+++ b/user/src/com/google/web/bindery/autobean/shared/Splittable.java
@@ -136,6 +136,13 @@
   boolean isUndefined(String key);
 
   /**
+   * Removes a tag value from the Splittable.
+   *
+   * @param key the key for the value to be removed
+   */
+  void removeReified(String key);
+
+  /**
    * Associates a tag value with the Splittable.
    */
   void setReified(String key, Object object);
diff --git a/user/src/com/google/web/bindery/autobean/shared/impl/SplittableList.java b/user/src/com/google/web/bindery/autobean/shared/impl/SplittableList.java
index 48fe0f6..0e076f8 100644
--- a/user/src/com/google/web/bindery/autobean/shared/impl/SplittableList.java
+++ b/user/src/com/google/web/bindery/autobean/shared/impl/SplittableList.java
@@ -94,8 +94,16 @@
     int newSize = data.size() - 1;
     for (int i = index; i < newSize; i++) {
       data.get(i + 1).assign(data, i);
-      data.setReified(String.valueOf(i), data.getReified(String.valueOf(i + 1)));
+      // reified value for index 'i'  may needs to be updated
+      if (data.isReified(String.valueOf(i + 1))) {
+        data.setReified(String.valueOf(i), data.getReified(String.valueOf(i + 1)));
+      } else if (data.isReified(String.valueOf(i))) {
+        // Remove outdated value. Will be regenerated if needed.
+        data.removeReified(String.valueOf(i));
+      }
     }
+    // clean-up last entry as one element has been removed
+    data.removeReified(String.valueOf(newSize));
     data.setSize(newSize);
     return toReturn;
   }
diff --git a/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java b/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java
index c8059a5..7ce0d54 100644
--- a/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java
+++ b/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java
@@ -264,6 +264,11 @@
     return !obj.has(key);
   }
 
+  @Override
+  public void removeReified(String key) {
+    reified.remove(key);
+  }
+
   public void setReified(String key, Object object) {
     reified.put(key, object);
   }
diff --git a/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java b/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java
index 5592e50..b899c85 100644
--- a/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java
+++ b/user/test/com/google/web/bindery/autobean/shared/SplittableTest.java
@@ -279,6 +279,23 @@
     assertEquals(data.getPayload(), normalize(data).getPayload());
   }
 
+  public void testSplittableListRemove() {
+    Splittable data = StringQuoter.split("[\"a\",\"b\",\"c\",\"d\"]");
+    SplittableList<String> list =
+        new SplittableList<String>(data, AutoBeanCodexImpl.valueCoder(String.class), testState);
+    assertEquals(list.size(), 4);
+    boolean removed = list.remove("b");
+    assertTrue(removed);
+    assertEquals(list.size(), 3);
+    assertTrue(list.equals(Arrays.asList("a", "c", "d")));
+    assertEquals("a", list.get(0));
+    assertTrue(list.contains("a"));
+    assertEquals("c", list.get(1));
+    assertTrue(list.contains("c"));
+    assertEquals("d", list.get(2));
+    assertTrue(list.contains("d"));
+  }
+
   public void testSplittableMapStringString() {
     Splittable data = StringQuoter.split("{\"foo\":\"bar\",\"baz\":\"quux\",\"isNull\":null}");
     assertTrue("isNull should be null", data.isNull("isNull"));