Add tests for const/range retrieval of effectively final fields.

Bug: 138913138, 138912149
Change-Id: I39ba6052d8e53466d0bf15b32c2fcd498cda9c61
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
new file mode 100644
index 0000000..ea96ead
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
@@ -0,0 +1,217 @@
+// 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.shaking;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class EffectivelyFinalInstanceFieldsTest extends TestBase {
+  private static final Class<?> MAIN = TestClass.class;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().build();
+  }
+
+  private final TestParameters parameters;
+
+  public EffectivelyFinalInstanceFieldsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testJVMOutput() throws Exception {
+    assumeTrue("Only run JVM reference on CF runtimes", parameters.isCfRuntime());
+    testForJvm()
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutputLines("The end");
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(EffectivelyFinalInstanceFieldsTest.class)
+        .addKeepMainRule(MAIN)
+        .enableInliningAnnotations()
+        .enableClassInliningAnnotations()
+        .enableMergeAnnotations()
+        .setMinApi(parameters.getRuntime())
+        .compile()
+        .inspect(codeInspector -> {
+          ClassSubject main = codeInspector.clazz(MAIN);
+          assertThat(main, isPresent());
+
+          MethodSubject mainMethod = main.mainMethod();
+          assertThat(mainMethod, isPresent());
+
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 1", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): effectively final, and default value is set.
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): not trivial; assigned only once in <init>
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 4", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): effectively final, and default value is set.
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 5", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): not trivial; assigned multiple times, but within a certain range.
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 6", JumboStringMode.ALLOW)));
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 7", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): effectively final, and default value is set.
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 8", JumboStringMode.ALLOW)));
+        })
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutputLines("The end");
+  }
+
+  static class TestClass {
+    public static void main(String... args) {
+      InstanceFieldWithoutInitialization_Z i1 = new InstanceFieldWithoutInitialization_Z();
+      if (i1.alwaysFalse) {
+        System.out.println("Dead code: 1");
+      }
+      InstanceFieldWithInitialization_Z i2 = new InstanceFieldWithInitialization_Z();
+      if (i2.alwaysFalse) {
+        System.out.println("Dead code: 2");
+      }
+      InstanceFieldWithNonTrivialInitialization_Z i3 =
+          new InstanceFieldWithNonTrivialInitialization_Z();
+      if (i3.alwaysFalse || !i3.alwaysTrue) {
+        System.out.println("Dead code: 3");
+      }
+      InstanceFieldWithoutInitialization_I i4 = new InstanceFieldWithoutInitialization_I();
+      if (i4.alwaysZero != 0) {
+        System.out.println("Dead code: 4");
+      }
+      InstanceFieldWithInitialization_I i5 = new InstanceFieldWithInitialization_I();
+      if (i5.alwaysZero != 0) {
+        System.out.println("Dead code: 5");
+      }
+      InstanceFieldWithRange_I i6 = new InstanceFieldWithRange_I();
+      i6.foo();
+      i6.bar();
+      if (i6.alwaysLessThanEight >= 8) {
+        System.out.println("Dead code: 6");
+      }
+      InstanceFieldWithoutInitialization_L i7 = new InstanceFieldWithoutInitialization_L();
+      if (i7.alwaysNull != null) {
+        System.out.println("Dead code: 7");
+      }
+      InstanceFieldWithInitialization_L i8 = new InstanceFieldWithInitialization_L();
+      if (i8.alwaysNull != null) {
+        System.out.println("Dead code: 8");
+      }
+      System.out.println("The end");
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithoutInitialization_Z {
+    boolean alwaysFalse;
+
+    InstanceFieldWithoutInitialization_Z() {
+    }
+  }
+
+  @NeverClassInline
+  @NeverMerge
+  static class InstanceFieldWithInitialization_Z {
+    boolean alwaysFalse;
+    InstanceFieldWithInitialization_Z() {
+      alwaysFalse = false;
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithNonTrivialInitialization_Z
+      extends InstanceFieldWithInitialization_Z {
+    boolean alwaysTrue;
+    InstanceFieldWithNonTrivialInitialization_Z() {
+      super();
+      alwaysTrue = alwaysFalse;
+      alwaysTrue = true;
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithoutInitialization_I {
+    int alwaysZero;
+
+    InstanceFieldWithoutInitialization_I() {
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithInitialization_I {
+    int alwaysZero;
+    InstanceFieldWithInitialization_I() {
+      alwaysZero = 0;
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithRange_I {
+    int alwaysLessThanEight;
+    InstanceFieldWithRange_I() {
+    }
+
+    @NeverInline
+    void foo() {
+      alwaysLessThanEight = 4;
+    }
+
+    @NeverInline
+    void bar() {
+      alwaysLessThanEight = 2;
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithoutInitialization_L {
+    Object alwaysNull;
+
+    InstanceFieldWithoutInitialization_L() {
+    }
+  }
+
+  @NeverClassInline
+  static class InstanceFieldWithInitialization_L {
+    Object alwaysNull;
+    InstanceFieldWithInitialization_L() {
+      alwaysNull = null;
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
new file mode 100644
index 0000000..0cc9afd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
@@ -0,0 +1,200 @@
+// 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.shaking;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class EffectivelyFinalStaticFieldsTest extends TestBase {
+  private static final Class<?> MAIN = TestClass.class;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().build();
+  }
+
+  private final TestParameters parameters;
+
+  public EffectivelyFinalStaticFieldsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testJVMOutput() throws Exception {
+    assumeTrue("Only run JVM reference on CF runtimes", parameters.isCfRuntime());
+    testForJvm()
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutputLines("The end");
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(EffectivelyFinalStaticFieldsTest.class)
+        .addKeepMainRule(MAIN)
+        .enableInliningAnnotations()
+        .enableClassInliningAnnotations()
+        .enableMergeAnnotations()
+        .setMinApi(parameters.getRuntime())
+        .compile()
+        .inspect(codeInspector -> {
+          ClassSubject main = codeInspector.clazz(MAIN);
+          assertThat(main, isPresent());
+
+          MethodSubject mainMethod = main.mainMethod();
+          assertThat(mainMethod, isPresent());
+
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 1", JumboStringMode.ALLOW)));
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): not trivial; assigned only once in <init>
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 4", JumboStringMode.ALLOW)));
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 5", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): not trivial; assigned multiple times, but within a certain range.
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 6", JumboStringMode.ALLOW)));
+          assertTrue(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 7", JumboStringMode.ALLOW)));
+          // TODO(b/138913138): effectively final, and default value is set.
+          assertFalse(
+              mainMethod.streamInstructions().noneMatch(
+                  i -> i.isConstString("Dead code: 8", JumboStringMode.ALLOW)));
+        })
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccess();
+        // TODO(b/138912149): should not be shrunk.
+        //.assertSuccessWithOutputLines("The end");
+  }
+
+  static class TestClass {
+    public static void main(String... args) {
+      if (StaticFieldWithoutInitialization_Z.alwaysFalse) {
+        System.out.println("Dead code: 1");
+      }
+      if (StaticFieldWithInitialization_Z.alwaysFalse) {
+        System.out.println("Dead code: 2");
+      }
+      if (StaticFieldWithNonTrivialInitialization_Z.alwaysFalse
+          || !StaticFieldWithNonTrivialInitialization_Z.alwaysTrue) {
+        System.out.println("Dead code: 3");
+      }
+      if (StaticFieldWithoutInitialization_I.alwaysZero != 0) {
+        System.out.println("Dead code: 4");
+      }
+      if (StaticFieldWithInitialization_I.alwaysZero != 0) {
+        System.out.println("Dead code: 5");
+      }
+      StaticFieldWithRange_I.foo();
+      StaticFieldWithRange_I.bar();
+      if (StaticFieldWithRange_I.alwaysLessThanEight >= 8) {
+        System.out.println("Dead code: 6");
+      }
+      if (StaticFieldWithoutInitialization_L.alwaysNull != null) {
+        System.out.println("Dead code: 7");
+      }
+      StaticFieldWithInitialization_L.not_clinit();
+      if (StaticFieldWithInitialization_L.alwaysNull != null) {
+        System.out.println("Dead code: 8");
+      }
+      System.out.println("The end");
+    }
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithoutInitialization_Z {
+    static boolean alwaysFalse;
+  }
+
+  @NeverClassInline
+  @NeverMerge
+  static class StaticFieldWithInitialization_Z {
+    static boolean alwaysFalse;
+    static {
+      alwaysFalse = false;
+    }
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithNonTrivialInitialization_Z
+      extends StaticFieldWithInitialization_Z {
+    static boolean alwaysTrue;
+    static {
+      alwaysTrue = alwaysFalse;
+      // TODO(b/138912149): should not be shrunk.
+      alwaysTrue = true;
+    }
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithoutInitialization_I {
+    static int alwaysZero;
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithInitialization_I {
+    static int alwaysZero;
+    static {
+      alwaysZero = 0;
+    }
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithRange_I {
+    static int alwaysLessThanEight;
+
+    @NeverInline
+    static void foo() {
+      alwaysLessThanEight = 4;
+    }
+
+    @NeverInline
+    static void bar() {
+      alwaysLessThanEight = 2;
+    }
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithoutInitialization_L {
+    static Object alwaysNull;
+  }
+
+  @NeverClassInline
+  static class StaticFieldWithInitialization_L {
+    static Object alwaysNull;
+    @NeverInline
+    static void not_clinit() {
+      alwaysNull = null;
+    }
+  }
+}