Backport Optional/OptionalInt/OptionalLong/OptionalDouble.isEmpty()

Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: I2c575b9ab62f5817a513ec9e9a15c1a2aac9c91a
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index d6650ab..bdc98f0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -507,6 +507,7 @@
           || options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
         initializeJava9OptionalMethodProviders(factory);
         initializeJava10OptionalMethodProviders(factory);
+        initializeJava11OptionalMethodProviders(factory);
       }
       if (appView.rewritePrefix.hasRewrittenType(factory.streamType)
           || options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
@@ -1520,6 +1521,32 @@
       }
     }
 
+    private void initializeJava11OptionalMethodProviders(DexItemFactory factory) {
+      // Optional{void,Int,Long,Double}.isEmpty()
+      DexType[] optionalTypes =
+          new DexType[] {
+              factory.optionalType,
+              factory.optionalDoubleType,
+              factory.optionalLongType,
+              factory.optionalIntType,
+          };
+      TemplateMethodFactory[] methodFactories =
+          new TemplateMethodFactory[]{
+              BackportedMethods::OptionalMethods_isEmpty,
+              BackportedMethods::OptionalMethods_isEmptyDouble,
+              BackportedMethods::OptionalMethods_isEmptyLong,
+              BackportedMethods::OptionalMethods_isEmptyInt
+          };
+      DexString name = factory.createString("isEmpty");
+      for (int i = 0; i < optionalTypes.length; i++) {
+        DexType optionalType = optionalTypes[i];
+        DexProto proto = factory.createProto(factory.booleanType);
+        DexMethod method = factory.createMethod(optionalType, proto, name);
+        addProvider(
+            new StatifyingMethodGenerator(method, methodFactories[i], "isEmpty", optionalType));
+      }
+    }
+
     private void initializeStreamMethodProviders(DexItemFactory factory) {
       // Stream
       DexType streamType = factory.streamType;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index bd87524..8440fc2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -5170,6 +5170,130 @@
         ImmutableList.of());
   }
 
+  public static CfCode OptionalMethods_isEmpty(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Optional;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_isEmptyDouble(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_isEmptyInt(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalInt;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_isEmptyLong(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalLong;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode OptionalMethods_or(InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
diff --git a/src/test/examplesJava11/backport/OptionalBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalBackportJava11Main.java
new file mode 100644
index 0000000..d1f6fa1
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalBackportJava11Main.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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 backport;
+
+import java.util.Optional;
+
+public final class OptionalBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    Optional<String> present = Optional.of("hey");
+    assertFalse(present.isEmpty());
+
+    Optional<String> absent = Optional.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java
new file mode 100644
index 0000000..1fa5617
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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 backport;
+
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    OptionalDouble present = OptionalDouble.of(2d);
+    assertFalse(present.isEmpty());
+
+    OptionalDouble absent = OptionalDouble.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java
new file mode 100644
index 0000000..9d1a09a
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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 backport;
+
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    OptionalInt present = OptionalInt.of(2);
+    assertFalse(present.isEmpty());
+
+    OptionalInt absent = OptionalInt.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java
new file mode 100644
index 0000000..573bbba
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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 backport;
+
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    OptionalLong present = OptionalLong.of(2L);
+    assertFalse(present.isEmpty());
+
+    OptionalLong absent = OptionalLong.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
new file mode 100644
index 0000000..dee14c1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalBackportJava11Test(TestParameters parameters) {
+    super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
new file mode 100644
index 0000000..981e1e2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalDoubleBackportJava11Test(TestParameters parameters) {
+    super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
new file mode 100644
index 0000000..e594db3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalIntBackportJava11Test(TestParameters parameters) {
+    super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
new file mode 100644
index 0000000..bc1f4aa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalLongBackportJava11Test(TestParameters parameters) {
+    super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
index 6a1bbc2..6fb1a83 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
@@ -100,4 +100,20 @@
       return DoubleStream.empty();
     }
   }
+
+  public static boolean isEmpty(Optional<?> receiver) {
+    return !receiver.isPresent();
+  }
+
+  public static boolean isEmptyInt(OptionalInt receiver) {
+    return !receiver.isPresent();
+  }
+
+  public static boolean isEmptyLong(OptionalLong receiver) {
+    return !receiver.isPresent();
+  }
+
+  public static boolean isEmptyDouble(OptionalDouble receiver) {
+    return !receiver.isPresent();
+  }
 }