Implement first version of proto lite shrinker.

Bug:
Change-Id: Ia77e68cfd634f38954cdcbe1537fd86937ff9720
diff --git a/src/test/examples/enumproto/Enumproto.java b/src/test/examples/enumproto/Enumproto.java
new file mode 100644
index 0000000..9176378
--- /dev/null
+++ b/src/test/examples/enumproto/Enumproto.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package enumproto;
+
+
+import enumproto.GeneratedEnumProto.Enum;
+import enumproto.three.GeneratedEnumProto.EnumThree;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class Enumproto {
+
+  private static final byte[] WITH_ALL_FIELDS = new byte[]{6, 8, 42, 16, 2, 24, 3};
+  private static final byte[] WITH_DEFAULT_FOR_ENUM = new byte[]{2, 8, 42};
+
+
+  public static void main(String... args) throws IOException {
+    readProtoAndPrintDaEnum(WITH_ALL_FIELDS);
+    readProtoAndPrintDaEnum(WITH_DEFAULT_FOR_ENUM);
+    readProtoThreeAndPrintDaEnum(WITH_ALL_FIELDS);
+    readProtoThreeAndPrintDaEnum(WITH_DEFAULT_FOR_ENUM);
+    roundTrip(WITH_ALL_FIELDS);
+    roundTrip(WITH_DEFAULT_FOR_ENUM);
+    roundTripThree(WITH_ALL_FIELDS);
+    roundTripThree(WITH_DEFAULT_FOR_ENUM);
+  }
+
+  private static void readProtoAndPrintDaEnum(byte[] bytes) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+    Enum.Builder builder = Enum.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Enum buffer = builder.build();
+    System.out.println(buffer.getEnum());
+  }
+
+  private static void readProtoThreeAndPrintDaEnum(byte[] bytes) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+    EnumThree.Builder builder = EnumThree.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    EnumThree buffer = builder.build();
+    System.out.println(buffer.getEnum());
+  }
+
+  private static void roundTrip(byte[] bytes) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+    Enum.Builder builder = Enum.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Enum buffer = builder.build();
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    buffer.writeDelimitedTo(output);
+    readProtoAndPrintDaEnum(output.toByteArray());
+  }
+
+  private static void roundTripThree(byte[] bytes) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+    EnumThree.Builder builder = EnumThree.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    EnumThree buffer = builder.build();
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    buffer.writeDelimitedTo(output);
+    readProtoThreeAndPrintDaEnum(output.toByteArray());
+  }
+
+}
diff --git a/src/test/examples/enumproto/enum.proto b/src/test/examples/enumproto/enum.proto
new file mode 100644
index 0000000..0fa5695
--- /dev/null
+++ b/src/test/examples/enumproto/enum.proto
@@ -0,0 +1,25 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package enumproto;
+
+option java_outer_classname = "GeneratedEnumProto";
+
+message Enum {
+  required int32 id = 1;
+  enum DaEnum {
+    UNKOWN = 0;
+    KNOWN = 1;
+    BELIEF = 2;
+  }
+  optional DaEnum enum = 2;
+  enum OtherEnum {
+    BLACK = 0;
+    RED = 1;
+    GREEN = 2;
+    OKALALALA = 3;
+  }
+  optional OtherEnum other = 3;
+}
+
diff --git a/src/test/examples/enumproto/enum_three.proto b/src/test/examples/enumproto/enum_three.proto
new file mode 100644
index 0000000..a2731fb
--- /dev/null
+++ b/src/test/examples/enumproto/enum_three.proto
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto3";
+package enumproto.three;
+
+option java_outer_classname = "GeneratedEnumProto";
+
+message EnumThree {
+  int32 id = 1;
+  enum DaEnum {
+    UNKOWN = 0;
+    KNOWN = 1;
+    BELIEF = 2;
+  }
+  DaEnum enum = 2;
+  enum OtherEnum {
+    BLACK = 0;
+    RED = 1;
+    GREEN = 2;
+    OKALALALA = 3;
+  }
+  OtherEnum other = 3;
+}
+
diff --git a/src/test/examples/enumproto/keep-rules.txt b/src/test/examples/enumproto/keep-rules.txt
new file mode 100644
index 0000000..088f88f
--- /dev/null
+++ b/src/test/examples/enumproto/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class enumproto.Enumproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/nestedproto1/Nestedproto.java b/src/test/examples/nestedproto1/Nestedproto.java
new file mode 100644
index 0000000..fe1a535
--- /dev/null
+++ b/src/test/examples/nestedproto1/Nestedproto.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package nestedproto1;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import nestedproto1.GeneratedNestedProto.Outer;
+
+public class Nestedproto {
+
+  private static final byte[] NESTED_MESSAGE_WITH_BOTH = new byte[] {25, 8, 42, 18, 12, 8, 1, 18, 8,
+      105, 110, 110, 101, 114, 79, 110, 101, 26, 7, 8, 2, 21, 0, 0, -10, 66};
+
+  private static final byte[] NESTED_MESSAGE_WITH_ONE = new byte[]{16, 8, 42, 18, 12, 8, 1, 18, 8,
+      105,
+      110, 110, 101, 114, 79, 110, 101};
+
+  public static void main(String... args) throws IOException {
+    testWith(NESTED_MESSAGE_WITH_BOTH);
+    testWith(NESTED_MESSAGE_WITH_ONE);
+  }
+
+  public static void testWith(byte[] data) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(data);
+    Outer.Builder builder = Outer.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Outer outer = builder.build();
+    System.out.println(outer.getInner().getOther());
+  }
+}
diff --git a/src/test/examples/nestedproto1/keep-rules.txt b/src/test/examples/nestedproto1/keep-rules.txt
new file mode 100644
index 0000000..1c47672
--- /dev/null
+++ b/src/test/examples/nestedproto1/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class nestedproto1.Nestedproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/nestedproto1/nested.proto b/src/test/examples/nestedproto1/nested.proto
new file mode 100644
index 0000000..0d05749
--- /dev/null
+++ b/src/test/examples/nestedproto1/nested.proto
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package nestedproto1;
+
+option java_outer_classname = "GeneratedNestedProto";
+
+message NestedOne {
+  required int32 id = 1;
+  optional string other = 2;
+}
+
+message NestedTwo {
+  required int32 id = 1;
+  optional float other = 2;
+}
+
+message Outer {
+  required int32 id = 1;
+  required NestedOne inner = 2;
+  optional NestedTwo inner2 = 3;
+}
+
diff --git a/src/test/examples/nestedproto2/Nestedproto.java b/src/test/examples/nestedproto2/Nestedproto.java
new file mode 100644
index 0000000..59217de
--- /dev/null
+++ b/src/test/examples/nestedproto2/Nestedproto.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package nestedproto2;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import nestedproto2.GeneratedNestedProto.Outer;
+
+public class Nestedproto {
+
+  private static final byte[] NESTED_MESSAGE_WITH_BOTH = new byte[]{25, 8, 42, 18, 12, 8, 1, 18, 8,
+      105, 110, 110, 101, 114, 79, 110, 101, 26, 7, 8, 2, 21, 0, 0, -10, 66};
+
+  private static final byte[] NESTED_MESSAGE_WITH_ONE = new byte[]{16, 8, 42, 18, 12, 8, 1, 18, 8,
+      105,
+      110, 110, 101, 114, 79, 110, 101};
+
+  // Test that all fields remain when roundtripping with removed fields.
+  public static void main(String... args) throws IOException {
+    testWith(NESTED_MESSAGE_WITH_BOTH);
+    testWith(NESTED_MESSAGE_WITH_ONE);
+  }
+
+  private static void testWith(byte[] data) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(data);
+    Outer.Builder builder = Outer.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    builder.setId(1982);
+    Outer outer = builder.build();
+    outer.writeTo(System.out);
+  }
+}
diff --git a/src/test/examples/nestedproto2/keep-rules.txt b/src/test/examples/nestedproto2/keep-rules.txt
new file mode 100644
index 0000000..87c9218
--- /dev/null
+++ b/src/test/examples/nestedproto2/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class nestedproto2.Nestedproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/nestedproto2/nested.proto b/src/test/examples/nestedproto2/nested.proto
new file mode 100644
index 0000000..ac56f40
--- /dev/null
+++ b/src/test/examples/nestedproto2/nested.proto
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package nestedproto2;
+
+option java_outer_classname = "GeneratedNestedProto";
+
+message NestedOne {
+  required int32 id = 1;
+  optional string other = 2;
+}
+
+message NestedTwo {
+  required int32 id = 1;
+  optional float other = 2;
+}
+
+message Outer {
+  required int32 id = 1;
+  required NestedOne inner = 2;
+  optional NestedTwo inner2 = 3;
+}
+
diff --git a/src/test/examples/oneofproto/Oneofproto.java b/src/test/examples/oneofproto/Oneofproto.java
new file mode 100644
index 0000000..261705f
--- /dev/null
+++ b/src/test/examples/oneofproto/Oneofproto.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package oneofproto;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import oneofproto.GeneratedOneOfProto.Oneof;
+
+public class Oneofproto {
+
+  private static final byte[] WITH_BOOL_FIELD = new byte[]{4, 8, 42, 24, 1};
+  private static final byte[] WITH_FLOAT_FIELD = new byte[]{7, 8, 42, 21, 0, 0, -10, 66};
+  private static final byte[] WITH_STRING_FIELD = new byte[]{9, 8, 42, 34, 5, 104, 101, 108, 108,
+      111};
+  private static final byte[] WITH_NO_FIELD = new byte[]{2, 8, 42};
+
+
+  public static void main(String... args) throws IOException {
+    roundTrip(WITH_BOOL_FIELD);
+    roundTrip(WITH_FLOAT_FIELD);
+    roundTrip(WITH_STRING_FIELD);
+    roundTrip(WITH_NO_FIELD);
+  }
+
+  private static void roundTrip(byte[] data) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(data);
+    Oneof.Builder builder = Oneof.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Oneof oneof = builder.build();
+    ByteArrayOutputStream output = new ByteArrayOutputStream();
+    oneof.writeDelimitedTo(output);
+    System.out.println(Arrays.toString(output.toByteArray()));
+  }
+
+}
diff --git a/src/test/examples/oneofproto/keep-rules.txt b/src/test/examples/oneofproto/keep-rules.txt
new file mode 100644
index 0000000..70f00f1
--- /dev/null
+++ b/src/test/examples/oneofproto/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class oneofproto.Oneofproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/oneofproto/oneof.proto b/src/test/examples/oneofproto/oneof.proto
new file mode 100644
index 0000000..c5a67a1
--- /dev/null
+++ b/src/test/examples/oneofproto/oneof.proto
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package oneofproto;
+
+option java_outer_classname = "GeneratedOneOfProto";
+
+message Oneof {
+  required int32 id = 1;
+  oneof otherfields {
+    float floatField = 2;
+    bool boolField = 3;
+    string stringField = 4;
+  }
+}
+
diff --git a/src/test/examples/protowithexts/withexts.proto b/src/test/examples/protowithexts/withexts.proto
new file mode 100644
index 0000000..d384173
--- /dev/null
+++ b/src/test/examples/protowithexts/withexts.proto
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package protowithexts;
+
+option java_outer_classname = "GeneratedProtoWithExts";
+
+message Simple {
+  required int32 id = 1;
+
+  optional int32 other = 2;
+
+  extensions 10 to 19;
+}
+
+extend Simple {
+  optional string extra = 10;
+}
diff --git a/src/test/examples/repeatedproto/Repeatedproto.java b/src/test/examples/repeatedproto/Repeatedproto.java
new file mode 100644
index 0000000..280070d
--- /dev/null
+++ b/src/test/examples/repeatedproto/Repeatedproto.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package repeatedproto;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import repeatedproto.GeneratedRepeatedProto.Repeated;
+
+public class Repeatedproto {
+
+  private static final byte[] WITH_ALL_FIELDS = new byte[]{29, 8, 123, 18, 3, 111, 110, 101, 18, 3,
+      116, 119, 111, 18, 5, 116, 104, 114, 101, 101, 24, 1, 34, 2, 8, 42, 34, 2, 8, 42};
+
+  public static void main(String... args) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(WITH_ALL_FIELDS);
+    Repeated.Builder builder = Repeated.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Repeated repeated = builder.build();
+    System.out.println(repeated.getRepeatedList());
+  }
+}
diff --git a/src/test/examples/repeatedproto/keep-rules.txt b/src/test/examples/repeatedproto/keep-rules.txt
new file mode 100644
index 0000000..3d02352
--- /dev/null
+++ b/src/test/examples/repeatedproto/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class repeatedproto.Repeatedproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/repeatedproto/repeated.proto b/src/test/examples/repeatedproto/repeated.proto
new file mode 100644
index 0000000..7414e6f
--- /dev/null
+++ b/src/test/examples/repeatedproto/repeated.proto
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package repeatedproto;
+
+option java_outer_classname = "GeneratedRepeatedProto";
+
+message Repeated {
+  required int32 id = 1;
+  repeated string repeated = 2;
+  repeated bool other = 3;
+
+  message Sub {
+    required int32 value = 1;
+  }
+
+  repeated Sub sub = 4;
+}
+
diff --git a/src/test/examples/repeatedproto/repeated_three.proto b/src/test/examples/repeatedproto/repeated_three.proto
new file mode 100644
index 0000000..7da7881
--- /dev/null
+++ b/src/test/examples/repeatedproto/repeated_three.proto
@@ -0,0 +1,15 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto3";
+package repeatedproto.three;
+
+option java_outer_classname = "GeneratedRepeatedProto";
+
+
+message RepeatedThree {
+  int32 id = 1;
+  repeated string repeated = 2;
+  repeated bool other = 3;
+}
+
diff --git a/src/test/examples/simpleproto1/Simpleproto.java b/src/test/examples/simpleproto1/Simpleproto.java
new file mode 100644
index 0000000..d07ce8d
--- /dev/null
+++ b/src/test/examples/simpleproto1/Simpleproto.java
@@ -0,0 +1,56 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package simpleproto1;
+
+import com.google.protobuf.UninitializedMessageException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import simpleproto1.GeneratedSimpleProto.Simple;
+
+public class Simpleproto {
+
+  private static final byte[] WITH_REQUIRED_FIELDS = new byte[]{7, 8, 42, 21, 0, 0, -10, 66};
+  private static final byte[] WITH_MISSING_FIELD = new byte[]{2, 8, 42};
+
+
+  public static void main(String... args) throws IOException {
+    readProtoWithAllReqFields();
+    partialBuildFails();
+    partialReadFails();
+  }
+
+  private static void partialBuildFails() {
+    Simple.Builder builder = Simple.newBuilder();
+    builder.setId(32);
+    try {
+      builder.build();
+    } catch (UninitializedMessageException e) {
+      System.out.println("got exception");
+    }
+  }
+
+  private static void partialReadFails() throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(WITH_MISSING_FIELD);
+    Simple.Builder builder = Simple.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    try {
+      builder.build();
+    } catch (UninitializedMessageException e) {
+      System.out.println("got exception");
+    }
+  }
+
+  private static void readProtoWithAllReqFields() throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(WITH_REQUIRED_FIELDS);
+    Simple.Builder builder = Simple.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Simple simple = builder.build();
+    ByteArrayOutputStream output = new ByteArrayOutputStream(WITH_REQUIRED_FIELDS.length);
+    simple.writeDelimitedTo(output);
+    System.out.println(Arrays.toString(output.toByteArray()));
+    System.out.println(Arrays.equals(WITH_REQUIRED_FIELDS, output.toByteArray()));
+  }
+}
diff --git a/src/test/examples/simpleproto1/keep-rules.txt b/src/test/examples/simpleproto1/keep-rules.txt
new file mode 100644
index 0000000..3c3c33f
--- /dev/null
+++ b/src/test/examples/simpleproto1/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class simpleproto1.Simpleproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/simpleproto1/simple.proto b/src/test/examples/simpleproto1/simple.proto
new file mode 100644
index 0000000..f4e1be4
--- /dev/null
+++ b/src/test/examples/simpleproto1/simple.proto
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package simpleproto1;
+
+option java_outer_classname = "GeneratedSimpleProto";
+
+message Simple {
+  required int32 id = 1;
+  required float unusedRequired = 2;
+  optional bool other = 3;
+}
+
diff --git a/src/test/examples/simpleproto2/Simpleproto.java b/src/test/examples/simpleproto2/Simpleproto.java
new file mode 100644
index 0000000..f333d72
--- /dev/null
+++ b/src/test/examples/simpleproto2/Simpleproto.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package simpleproto2;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import simpleproto2.GeneratedSimpleProto.Simple;
+
+/**
+ * A class that only uses a has method but otherwise ignores the value of a field.
+ */
+public class Simpleproto {
+
+  private static final byte[] WITHOUT_HASME_FIELD = new byte[]{2, 8, 42};
+  private static final byte[] WITH_HASME_FIELD = new byte[]{7, 8, 42, 21, 0, 0, -10, 66};
+
+  public static void main(String... args) throws IOException {
+    testHasWorks(WITHOUT_HASME_FIELD, false);
+    testHasWorks(WITH_HASME_FIELD, true);
+  }
+
+  private static void testHasWorks(byte[] msg, boolean expected) throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(msg);
+    Simple.Builder builder = Simple.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Simple simple = builder.build();
+    System.out.println("Expected " + expected + " and got " + simple.hasHasMe());
+  }
+}
diff --git a/src/test/examples/simpleproto2/keep-rules.txt b/src/test/examples/simpleproto2/keep-rules.txt
new file mode 100644
index 0000000..8f9c93e
--- /dev/null
+++ b/src/test/examples/simpleproto2/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class simpleproto2.Simpleproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/simpleproto2/simple.proto b/src/test/examples/simpleproto2/simple.proto
new file mode 100644
index 0000000..b9173e9
--- /dev/null
+++ b/src/test/examples/simpleproto2/simple.proto
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto2";
+package simpleproto2;
+
+option java_outer_classname = "GeneratedSimpleProto";
+
+message Simple {
+  required int32 id = 1;
+  optional float hasMe = 2;
+  optional int32 other = 3;
+}
+
diff --git a/src/test/examples/simpleproto3/Simpleproto.java b/src/test/examples/simpleproto3/Simpleproto.java
new file mode 100644
index 0000000..2cdbae8
--- /dev/null
+++ b/src/test/examples/simpleproto3/Simpleproto.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package simpleproto3;
+
+import com.google.protobuf.UninitializedMessageException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import simpleproto3.GeneratedSimpleProto.Simple;
+
+public class Simpleproto {
+
+  private static final byte[] WITH_REQUIRED_FIELDS = new byte[]{7, 8, 42, 21, 0, 0, -10, 66};
+  private static final byte[] WITH_MISSING_FIELD = new byte[]{2, 8, 42};
+
+
+  public static void main(String... args) throws IOException {
+    readProtoWithAllReqFields();
+    partialBuildFails();
+    partialReadFails();
+  }
+
+  private static void partialBuildFails() {
+    Simple.Builder builder = Simple.newBuilder();
+    builder.setId(32);
+    try {
+      builder.build();
+    } catch (UninitializedMessageException e) {
+      System.out.println("got exception");
+    }
+  }
+
+  private static void partialReadFails() throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(WITH_MISSING_FIELD);
+    Simple.Builder builder = Simple.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    try {
+      builder.build();
+    } catch (UninitializedMessageException e) {
+      System.out.println("got exception");
+    }
+  }
+
+  private static void readProtoWithAllReqFields() throws IOException {
+    ByteArrayInputStream input = new ByteArrayInputStream(WITH_REQUIRED_FIELDS);
+    Simple.Builder builder = Simple.newBuilder();
+    builder.mergeDelimitedFrom(input);
+    Simple simple = builder.build();
+    ByteArrayOutputStream output = new ByteArrayOutputStream(WITH_REQUIRED_FIELDS.length);
+    simple.writeDelimitedTo(output);
+    System.out.println(isContained(WITH_REQUIRED_FIELDS, output.toByteArray()));
+  }
+
+  // After shaking, the serialized proto will no longer contain fields that are not referenced.
+  private static boolean isContained(byte[] fullBytes, byte[] reducedBytes) {
+    int j = 1;
+    for (int i = 1; i < fullBytes.length && j < reducedBytes.length; i++) {
+      if (fullBytes[i] == reducedBytes[j]) {
+        j++;
+      }
+    }
+    return j == reducedBytes.length;
+  }
+}
diff --git a/src/test/examples/simpleproto3/keep-rules.txt b/src/test/examples/simpleproto3/keep-rules.txt
new file mode 100644
index 0000000..186e9f8
--- /dev/null
+++ b/src/test/examples/simpleproto3/keep-rules.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class simpleproto3.Simpleproto {
+  public static void main(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
diff --git a/src/test/examples/simpleproto3/simple.proto b/src/test/examples/simpleproto3/simple.proto
new file mode 100644
index 0000000..87512d1
--- /dev/null
+++ b/src/test/examples/simpleproto3/simple.proto
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// // for details. All rights reserved. Use of this source code is governed by a
+// // BSD-style license that can be found in the LICENSE file.
+syntax = "proto3";
+package simpleproto3;
+
+option java_outer_classname = "GeneratedSimpleProto";
+
+message Simple {
+  int32 id = 1;
+  float unusedRequired = 2;
+  bool other = 3;
+}
+
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
index afa437e..ca713fd 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
@@ -9,27 +9,22 @@
 import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 
 public class R8GMSCoreV10DeployJarVerificationTest extends GMSCoreDeployJarVerificationTest {
 
-  private void configureDeterministic(InternalOptions options) {
-    options.removeSwitchMaps = false;
-  }
-
   @Test
   public void buildFromDeployJar()
       // TODO(tamaskenez): set hasReference = true when we have the noshrink file for V10
       throws ExecutionException, IOException, ProguardRuleParserException, CompilationException {
     AndroidApp app1 = buildFromDeployJar(
         CompilerUnderTest.R8, CompilationMode.RELEASE,
-        GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false, this::configureDeterministic);
+        GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false);
     AndroidApp app2 = buildFromDeployJar(
         CompilerUnderTest.R8, CompilationMode.RELEASE,
-        GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false, this::configureDeterministic);
+        GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false);
 
     // Verify that the result of the two compilations was the same.
     assertIdenticalApplications(app1, app2);
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
index 2640f13..766de9d 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
@@ -20,7 +20,6 @@
 
   private void configureDeterministic(InternalOptions options) {
     options.skipMinification = true;
-    options.removeSwitchMaps = false;
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
index 646a481..4e8881a 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
@@ -13,7 +13,6 @@
 import java.nio.file.Paths;
 import java.util.concurrent.ExecutionException;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class RewriteSwitchMapsTest extends TestBase {
@@ -24,8 +23,6 @@
       "-keep class switchmaps.Switches { public static void main(...); } " +
           "-dontobfuscate";
 
-  // TODO(sgjesse): Re-enable this when the switch-map extraction has been fixed.
-  @Ignore
   @Test
   public void checkSwitchMapsRemoved()
       throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index 3435577..99be74a 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -372,6 +372,80 @@
         subclass.method("double", "anotherMethod", ImmutableList.of("double")).isPresent());
   }
 
+  private static void simpleproto1UnusedFieldIsGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("simpleproto1.GeneratedSimpleProto$Simple");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertFalse(protoClass.field("boolean", "other_").isPresent());
+  }
+
+  private static void simpleproto2UnusedFieldsAreGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("simpleproto2.GeneratedSimpleProto$Simple");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertFalse(protoClass.field("int", "id_").isPresent());
+    Assert.assertFalse(protoClass.field("float", "hasMe_").isPresent());
+    Assert.assertFalse(protoClass.field("int", "other_").isPresent());
+  }
+
+  private static void nestedproto1UnusedFieldsAreGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("nestedproto1.GeneratedNestedProto$Outer");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertFalse(protoClass.field("int", "id_").isPresent());
+    Assert.assertTrue(
+        protoClass.field("nestedproto1.GeneratedNestedProto$NestedOne", "inner_").isPresent());
+    Assert.assertFalse(
+        protoClass.field("nestedproto1.GeneratedNestedProto$NestedTwo", "inner2_").isPresent());
+    ClassSubject nestedOne = inspector.clazz("nestedproto1.GeneratedNestedProto$NestedOne");
+    Assert.assertTrue(nestedOne.isPresent());
+    Assert.assertTrue(nestedOne.field("java.lang.String", "other_").isPresent());
+    Assert.assertFalse(nestedOne.field("int", "id_").isPresent());
+    Assert.assertFalse(inspector.clazz("nestedproto1.GeneratedNestedProto$NestedTwo").isPresent());
+  }
+
+  private static void nestedproto2UnusedFieldsAreGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("nestedproto2.GeneratedNestedProto$Outer");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertTrue(protoClass.field("int", "id_").isPresent());
+    Assert.assertFalse(
+        protoClass.field("nestedproto2.GeneratedNestedProto$NestedOne", "inner_").isPresent());
+    Assert.assertFalse(
+        protoClass.field("nestedproto2.GeneratedNestedProto$NestedTwo", "inner2_").isPresent());
+    Assert.assertFalse(inspector.clazz("nestedproto2.GeneratedNestedProto$NestedOne").isPresent());
+    Assert.assertFalse(inspector.clazz("nestedproto2.GeneratedNestedProto$NestedTwo").isPresent());
+  }
+
+
+  private static void enumprotoUnusedFieldsAreGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("enumproto.GeneratedEnumProto$Enum");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertFalse(protoClass.field("int", "id_").isPresent());
+    Assert.assertTrue(protoClass.field("int", "enum_").isPresent());
+    Assert.assertFalse(protoClass.field("int", "other_").isPresent());
+    ClassSubject protoThreeClass = inspector.clazz("enumproto.three.GeneratedEnumProto$EnumThree");
+    Assert.assertTrue(protoThreeClass.isPresent());
+    Assert.assertFalse(protoThreeClass.field("int", "id_").isPresent());
+    Assert.assertTrue(protoThreeClass.field("int", "enum_").isPresent());
+    Assert.assertFalse(protoThreeClass.field("int", "other_").isPresent());
+  }
+
+  private static void repeatedUnusedFieldsAreGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("repeatedproto.GeneratedRepeatedProto$Repeated");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertFalse(protoClass.field("int", "id_").isPresent());
+    Assert.assertTrue(
+        protoClass.field("com.google.protobuf.Internal$ProtobufList", "repeated_").isPresent());
+    Assert.assertFalse(
+        protoClass.field("com.google.protobuf.Internal$ProtobufList", "sub_").isPresent());
+    Assert.assertFalse(
+        protoClass.field("com.google.protobuf.Internal$BooleanList", "other_").isPresent());
+  }
+
+  private static void oneofprotoUnusedFieldsAreGone(DexInspector inspector) {
+    ClassSubject protoClass = inspector.clazz("oneofproto.GeneratedOneOfProto$Oneof");
+    Assert.assertTrue(protoClass.isPresent());
+    Assert.assertFalse(protoClass.field("int", "id_").isPresent());
+    Assert.assertFalse(protoClass.field("Object", "otherfields_").isPresent());
+  }
+
   private static List<String> names =
       ImmutableList.of("pqr", "vw$", "abc", "def", "stu", "ghi", "jkl", "ea", "xyz_", "mno");
 
@@ -557,7 +631,15 @@
             "assumevalues5",
             "annotationremoval",
             "memberrebinding2",
-            "memberrebinding3");
+            "memberrebinding3",
+            "simpleproto1",
+            "simpleproto2",
+            "simpleproto3",
+            "nestedproto1",
+            "nestedproto2",
+            "enumproto",
+            "repeatedproto",
+            "oneofproto");
 
     // Keys can be the name of the test or the name of the test followed by a colon and the name
     // of the keep file.
@@ -614,6 +696,20 @@
     inspections
         .put("annotationremoval:keep-rules-keep-innerannotation.txt",
             TreeShakingTest::annotationRemovalHasAllInnerClassAnnotations);
+    inspections
+        .put("simpleproto1:keep-rules.txt", TreeShakingTest::simpleproto1UnusedFieldIsGone);
+    inspections
+        .put("simpleproto2:keep-rules.txt", TreeShakingTest::simpleproto2UnusedFieldsAreGone);
+    inspections
+        .put("nestedproto1:keep-rules.txt", TreeShakingTest::nestedproto1UnusedFieldsAreGone);
+    inspections
+        .put("nestedproto2:keep-rules.txt", TreeShakingTest::nestedproto2UnusedFieldsAreGone);
+    inspections
+        .put("enumproto:keep-rules.txt", TreeShakingTest::enumprotoUnusedFieldsAreGone);
+    inspections
+        .put("repeatedproto:keep-rules.txt", TreeShakingTest::repeatedUnusedFieldsAreGone);
+    inspections
+        .put("oneofproto:keep-rules.txt", TreeShakingTest::oneofprotoUnusedFieldsAreGone);
 
     // Keys can be the name of the test or the name of the test followed by a colon and the name
     // of the keep file.
@@ -779,7 +875,7 @@
           Collections.singletonList(generated.toString()), mainClass, extraArtArgs, null);
       outputComparator.accept(output1, output2);
     } else {
-      ToolHelper.checkArtOutputIdentical(Collections.singletonList(originalDex),
+      String output = ToolHelper.checkArtOutputIdentical(Collections.singletonList(originalDex),
           Collections.singletonList(generated.toString()), mainClass,
           extraArtArgs, null);
     }