Merge "When no clear() is generated, still initialize fields."
diff --git a/java/pom.xml b/java/pom.xml
index 1f110d9..6c7191c 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -152,19 +152,19 @@
                   <arg value="../src/google/protobuf/unittest_repeated_merge_nano.proto" />
                 </exec>
                 <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
+                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
                   <arg value="--proto_path=../src" />
                   <arg value="--proto_path=src/test/java" />
                   <arg value="../src/google/protobuf/unittest_extension_nano.proto" />
                 </exec>
                 <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
+                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
                   <arg value="--proto_path=../src" />
                   <arg value="--proto_path=src/test/java" />
                   <arg value="../src/google/protobuf/unittest_extension_singular_nano.proto" />
                 </exec>
                 <exec executable="../src/protoc">
-                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
+                  <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true,generate_clone=true:target/generated-test-sources" />
                   <arg value="--proto_path=../src" />
                   <arg value="--proto_path=src/test/java" />
                   <arg value="../src/google/protobuf/unittest_extension_repeated_nano.proto" />
diff --git a/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
index 46cd86f..8244164 100644
--- a/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -184,4 +184,11 @@
         return (unknownFieldData == null || unknownFieldData.isEmpty()
                 ? 0 : unknownFieldData.hashCode());
     }
+
+    @Override
+    public M clone() throws CloneNotSupportedException {
+        M cloned = (M) super.clone();
+        InternalNano.cloneUnknownFieldData(this, cloned);
+        return cloned;
+    }
 }
diff --git a/java/src/main/java/com/google/protobuf/nano/Extension.java b/java/src/main/java/com/google/protobuf/nano/Extension.java
index 728f0dc..b4d3eb0 100644
--- a/java/src/main/java/com/google/protobuf/nano/Extension.java
+++ b/java/src/main/java/com/google/protobuf/nano/Extension.java
@@ -75,7 +75,7 @@
     public static final int TYPE_SINT64   = 18;
 
     // Note: these create...() methods take a long for the tag parameter,
-    // because tags are represented as unsigned longs, and these values exist
+    // because tags are represented as unsigned ints, and these values exist
     // in generated code as long values. However, they can fit in 32-bits, so
     // it's safe to cast them to int without loss of precision.
 
@@ -142,7 +142,7 @@
     protected final Class<T> clazz;
 
     /**
-     * Tag number of this extension.
+     * Tag number of this extension. The data should be viewed as an unsigned 32-bit value.
      */
     public final int tag;
 
diff --git a/java/src/main/java/com/google/protobuf/nano/FieldArray.java b/java/src/main/java/com/google/protobuf/nano/FieldArray.java
index ab923a4..473c161 100644
--- a/java/src/main/java/com/google/protobuf/nano/FieldArray.java
+++ b/java/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -37,7 +37,7 @@
  *
  * Based on {@link android.support.v4.util.SpareArrayCompat}.
  */
-class FieldArray {
+class FieldArray implements Cloneable {
     private static final FieldData DELETED = new FieldData();
     private boolean mGarbage = false;
 
@@ -270,4 +270,19 @@
         }
         return true;
     }
+
+    @Override
+    public final FieldArray clone() {
+        // Trigger GC so we compact and don't copy DELETED elements.
+        int size = size();
+        FieldArray clone = new FieldArray(size);
+        System.arraycopy(mFieldNumbers, 0, clone.mFieldNumbers, 0, size);
+        for (int i = 0; i < size; i++) {
+            if (mData[i] != null) {
+                clone.mData[i] = mData[i].clone();
+            }
+        }
+        clone.mSize = size;
+        return clone;
+    }
 }
diff --git a/java/src/main/java/com/google/protobuf/nano/FieldData.java b/java/src/main/java/com/google/protobuf/nano/FieldData.java
index e5b69aa..20a5142 100644
--- a/java/src/main/java/com/google/protobuf/nano/FieldData.java
+++ b/java/src/main/java/com/google/protobuf/nano/FieldData.java
@@ -39,7 +39,7 @@
  * Stores unknown fields. These might be extensions or fields that the generated API doesn't
  * know about yet.
  */
-class FieldData {
+class FieldData implements Cloneable {
     private Extension<?, ?> cachedExtension;
     private Object value;
     /** The serialised values for this object. Will be cleared if getValue is called */
@@ -187,4 +187,54 @@
         return result;
     }
 
+    @Override
+    public final FieldData clone() {
+        FieldData clone = new FieldData();
+        try {
+            clone.cachedExtension = cachedExtension;
+            if (unknownFieldData == null) {
+                clone.unknownFieldData = null;
+            } else {
+                clone.unknownFieldData.addAll(unknownFieldData);
+            }
+
+            // Whether we need to deep clone value depends on its type. Primitive reference types
+            // (e.g. Integer, Long etc.) are ok, since they're immutable. We need to clone arrays
+            // and messages.
+            if (value == null) {
+                // No cloning required.
+            } else if (value instanceof MessageNano) {
+                clone.value = ((MessageNano) value).clone();
+            } else if (value instanceof byte[]) {
+                clone.value = ((byte[]) value).clone();
+            } else if (value instanceof byte[][]) {
+                byte[][] valueArray = (byte[][]) value;
+                byte[][] cloneArray = new byte[valueArray.length][];
+                clone.value = cloneArray;
+                for (int i = 0; i < valueArray.length; i++) {
+                    cloneArray[i] = valueArray[i].clone();
+                }
+            } else if (value instanceof boolean[]) {
+                clone.value = ((boolean[]) value).clone();
+            } else if (value instanceof int[]) {
+                clone.value = ((int[]) value).clone();
+            } else if (value instanceof long[]) {
+                clone.value = ((long[]) value).clone();
+            } else if (value instanceof float[]) {
+                clone.value = ((float[]) value).clone();
+            } else if (value instanceof double[]) {
+                clone.value = ((double[]) value).clone();
+            } else if (value instanceof MessageNano[]) {
+                MessageNano[] valueArray = (MessageNano[]) value;
+                MessageNano[] cloneArray = new MessageNano[valueArray.length];
+                clone.value = cloneArray;
+                for (int i = 0; i < valueArray.length; i++) {
+                    cloneArray[i] = valueArray[i].clone();
+                }
+            }
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
 }
diff --git a/java/src/main/java/com/google/protobuf/nano/InternalNano.java b/java/src/main/java/com/google/protobuf/nano/InternalNano.java
index 90ca11d..c4adfa5 100644
--- a/java/src/main/java/com/google/protobuf/nano/InternalNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -330,4 +330,12 @@
     return result;
   }
 
+  // This avoids having to make FieldArray public.
+  public static void cloneUnknownFieldData(ExtendableMessageNano original,
+      ExtendableMessageNano cloned) {
+    if (original.unknownFieldData != null) {
+      cloned.unknownFieldData = (FieldArray) original.unknownFieldData.clone();
+    }
+  }
+
 }
diff --git a/java/src/main/java/com/google/protobuf/nano/MessageNano.java b/java/src/main/java/com/google/protobuf/nano/MessageNano.java
index 164f317..ea91b21 100644
--- a/java/src/main/java/com/google/protobuf/nano/MessageNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -187,4 +187,12 @@
     public String toString() {
         return MessageNanoPrinter.print(this);
     }
+
+    /**
+     * Provides support for cloning. This only works if you specify the generate_clone method.
+     */
+    @Override
+    public MessageNano clone() throws CloneNotSupportedException {
+        return (MessageNano) super.clone();
+    }
 }
diff --git a/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
index 2032e1a..bf34bed 100644
--- a/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
+++ b/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -42,6 +42,10 @@
 final class UnknownFieldData {
 
     final int tag;
+    /**
+     * Important: this should be treated as immutable, even though it's possible
+     * to change the array values.
+     */
     final byte[] bytes;
 
     UnknownFieldData(int tag, byte[] bytes) {
diff --git a/java/src/test/java/com/google/protobuf/NanoTest.java b/java/src/test/java/com/google/protobuf/NanoTest.java
index 81e57c0..4c3b416 100644
--- a/java/src/test/java/com/google/protobuf/NanoTest.java
+++ b/java/src/test/java/com/google/protobuf/NanoTest.java
@@ -3000,6 +3000,10 @@
     assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
     assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
     assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+
+    // Clone the message and ensure it's still equal.
+    Extensions.ExtendableMessage clone = message.clone();
+    assertEquals(clone, message);
   }
 
   public void testNullExtensions() throws Exception {
@@ -3814,6 +3818,22 @@
     assertTrue(Arrays.equals(nonPacked.enums, packed.enums));
   }
 
+  public void testClone() throws Exception {
+    // A simple message.
+    AnotherMessage anotherMessage = new AnotherMessage();
+    anotherMessage.string = "Hello";
+    anotherMessage.value = true;
+    anotherMessage.integers = new int[] { 1, 2, 3 };
+
+    AnotherMessage clone = anotherMessage.clone();
+    assertEquals(clone, anotherMessage);
+
+    // Verify it was a deep clone - changes to the clone shouldn't affect the
+    // original.
+    clone.integers[1] = 100;
+    assertFalse(clone.equals(anotherMessage));
+  }
+
   private void assertHasWireData(MessageNano message, boolean expected) {
     byte[] bytes = MessageNano.toByteArray(message);
     int wireLength = bytes.length;
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
index 8a59d32..99b316b 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -499,6 +499,14 @@
 }
 
 void RepeatedEnumFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null && this.$name$.length > 0) {\n"
+    "  cloned.$name$ = this.$name$.clone();\n"
+    "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
index 55bf635..8622463 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -106,6 +106,7 @@
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCodeCode(io::Printer* printer) const;
+  void GenerateFixClonedCode(io::Printer* printer) const;
 
  private:
   void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
index 61fc621..e015259 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -82,6 +82,7 @@
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
   virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
   virtual void GenerateHashCodeCode(io::Printer* printer) const = 0;
+  virtual void GenerateFixClonedCode(io::Printer* printer) const {}
 
  protected:
   const Params& params_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index b1e75e3..9ca06cd 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -152,6 +152,8 @@
       params.set_ignore_services(option_value == "true");
     } else if (option_name == "parcelable_messages") {
       params.set_parcelable_messages(option_value == "true");
+    } else if (option_name == "generate_clone") {
+      params.set_generate_clone(option_value == "true");
     } else {
       *error = "Ignore unknown javanano generator option: " + option_name;
     }
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index 4df3ae8..dcfb870 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -134,18 +134,23 @@
   }
   if (params_.store_unknown_fields() && params_.parcelable_messages()) {
     printer->Print(
-      "    com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
+      "    com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$>",
       "classname", descriptor_->name());
   } else if (params_.store_unknown_fields()) {
     printer->Print(
-      "    com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+      "    com.google.protobuf.nano.ExtendableMessageNano<$classname$>",
       "classname", descriptor_->name());
   } else if (params_.parcelable_messages()) {
     printer->Print(
-      "    com.google.protobuf.nano.android.ParcelableMessageNano {\n");
+      "    com.google.protobuf.nano.android.ParcelableMessageNano");
   } else {
     printer->Print(
-      "    com.google.protobuf.nano.MessageNano {\n");
+      "    com.google.protobuf.nano.MessageNano");
+  }
+  if (params_.generate_clone()) {
+    printer->Print(" implements java.lang.Cloneable {\n");
+  } else {
+    printer->Print(" {\n");
   }
   printer->Indent();
 
@@ -269,6 +274,10 @@
 
   GenerateClear(printer);
 
+  if (params_.generate_clone()) {
+    GenerateClone(printer);
+  }
+
   if (params_.generate_equals()) {
     GenerateEquals(printer);
     GenerateHashCode(printer);
@@ -486,6 +495,33 @@
   printer->Print("cachedSize = -1;\n");
 }
 
+void MessageGenerator::GenerateClone(io::Printer* printer) {
+  printer->Print(
+    "@Override\n"
+    "public $classname$ clone() {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+
+  printer->Print(
+    "$classname$ cloned;\n"
+    "try {\n"
+    "  cloned = ($classname$) super.clone();\n"
+    "} catch (java.lang.CloneNotSupportedException e) {\n"
+    "  throw new java.lang.AssertionError(e);\n"
+    "}\n",
+    "classname", descriptor_->name());
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i)).GenerateFixClonedCode(printer);
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "  return cloned;\n"
+    "}\n"
+    "\n");
+}
+
 void MessageGenerator::GenerateEquals(io::Printer* printer) {
   // Don't override if there are no fields. We could generate an
   // equals method that compares types, but often empty messages
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
index f53c1f7..1bb6557 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -80,6 +80,7 @@
   void GenerateFieldInitializers(io::Printer* printer);
   void GenerateEquals(io::Printer* printer);
   void GenerateHashCode(io::Printer* printer);
+  void GenerateClone(io::Printer* printer);
 
   const Params& params_;
   const Descriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
index a46081d..4752644 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -127,6 +127,14 @@
 }
 
 void MessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null) {\n"
+    "  cloned.$name$ = this.$name$.clone();\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (this.$name$ == null) { \n"
@@ -238,6 +246,19 @@
 }
 
 void RepeatedMessageFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null && this.$name$.length > 0) {\n"
+    "  cloned.$name$ = new $type$[this.$name$.length];\n"
+    "  for (int i = 0; i < this.$name$.length; i++) {\n"
+    "    if (this.$name$[i] != null) {\n"
+    "      cloned.$name$[i] = this.$name$[i].clone();\n"
+    "    }\n"
+    "  }\n"
+    "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (!com.google.protobuf.nano.InternalNano.equals(\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
index e94a37b..1edff25 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -58,6 +58,7 @@
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCodeCode(io::Printer* printer) const;
+  void GenerateFixClonedCode(io::Printer* printer) const;
 
  private:
   const FieldDescriptor* descriptor_;
@@ -80,6 +81,7 @@
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCodeCode(io::Printer* printer) const;
+  void GenerateFixClonedCode(io::Printer* printer) const;
 
  private:
   const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
index 4691f36..77bc717 100644
--- a/src/google/protobuf/compiler/javanano/javanano_params.h
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -66,6 +66,7 @@
   bool parcelable_messages_;
   bool reftypes_primitive_enums_;
   bool generate_clear_;
+  bool generate_clone_;
 
  public:
   Params(const string & base_name) :
@@ -81,7 +82,8 @@
     ignore_services_(false),
     parcelable_messages_(false),
     reftypes_primitive_enums_(false),
-    generate_clear_(true) {
+    generate_clear_(true),
+    generate_clone_(false) {
   }
 
   const string& base_name() const {
@@ -231,6 +233,13 @@
   bool generate_clear() const {
     return generate_clear_;
   }
+
+  void set_generate_clone(bool value) {
+    generate_clone_ = value;
+  }
+  bool generate_clone() const {
+    return generate_clone_;
+  }
 };
 
 }  // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index a3bc3a8..bda52c6 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -385,6 +385,14 @@
   }
 }
 
+void RepeatedPrimitiveFieldGenerator::
+GenerateFixClonedCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (this.$name$ != null && this.$name$.length > 0) {\n"
+    "  cloned.$name$ = this.$name$.clone();\n"
+    "}\n");
+}
+
 void PrimitiveFieldGenerator::
 GenerateEqualsCode(io::Printer* printer) const {
   // We define equality as serialized form equality. If generate_has(),
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
index c04a19b..5ace0de 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -108,6 +108,7 @@
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCodeCode(io::Printer* printer) const;
+  void GenerateFixClonedCode(io::Printer* printer) const;
 
  private:
   void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/unittest_extension_nano.proto b/src/google/protobuf/unittest_extension_nano.proto
index d1c5766..ca56b3d 100644
--- a/src/google/protobuf/unittest_extension_nano.proto
+++ b/src/google/protobuf/unittest_extension_nano.proto
@@ -16,6 +16,7 @@
 message AnotherMessage {
   optional string string = 1;
   optional bool value = 2;
+  repeated int32 integers = 3;
 }
 
 message ContainerMessage {