Add test for bug when accessing public fields on non-public ancestor
Bug: 76191597
Change-Id: I5c23a1f852d2135da5b7009f6b22c97316ff50a0
diff --git a/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
new file mode 100644
index 0000000..7733339
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
@@ -0,0 +1,70 @@
+// Copyright (c) 2018, 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.resolution;
+
+public class PublicFieldInnerClassTest {
+ public static final Class<?>[] CLASSES = {
+ PrivateBase.class,
+ PrivateSubclass.class,
+ PackageBase.class,
+ PackageSubclass.class,
+ ProtectedBase.class,
+ ProtectedSubclass.class,
+ PublicBase.class,
+ PublicSubclass.class,
+ PublicFieldInnerClassTest.class
+ };
+
+ private static class PrivateBase {
+ public int value;
+ }
+
+ private static class PrivateSubclass extends PrivateBase {
+ }
+
+ static class PackageBase {
+ public int value;
+ }
+
+ private static class PackageSubclass extends PackageBase {
+ }
+
+ protected static class ProtectedBase {
+ public int value;
+ }
+
+ private static class ProtectedSubclass extends ProtectedBase {
+ }
+
+ public static class PublicBase {
+ public int value;
+ }
+
+ private static class PublicSubclass extends PublicBase {
+ }
+
+ private static int getPrivate(PrivateSubclass instance) {
+ return instance.value;
+ }
+
+ private static int getPackage(PackageSubclass instance) {
+ return instance.value;
+ }
+
+ private static int getProtected(ProtectedSubclass instance) {
+ return instance.value;
+ }
+
+ private static int getPublic(PublicSubclass instance) {
+ return instance.value;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(getPrivate(new PrivateSubclass()));
+ System.out.println(getPackage(new PackageSubclass()));
+ System.out.println(getProtected(new ProtectedSubclass()));
+ System.out.println(getPublic(new PublicSubclass()));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTestRunner.java b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTestRunner.java
new file mode 100644
index 0000000..b10e5f8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTestRunner.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2018, 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.resolution;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.R8Command.Builder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.origin.Origin;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+
+public class PublicFieldInnerClassTestRunner extends TestBase {
+ static final Class CLASS = PublicFieldInnerClassTest.class;
+ static final Class<?>[] CLASSES = PublicFieldInnerClassTest.CLASSES;
+
+ @Test
+ public void testCf() throws Exception {
+ ProcessResult runInput =
+ ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());
+ assertEquals(0, runInput.exitCode);
+ Path outCf = temp.getRoot().toPath().resolve("cf.jar");
+ build(new ClassFileConsumer.ArchiveConsumer(outCf));
+ ProcessResult runCf = ToolHelper.runJava(outCf, CLASS.getCanonicalName());
+ // TODO(b/76191597): Change to assertEquals when bug is fixed
+ assertNotEquals(runInput.toString(), runCf.toString());
+ assertNotEquals(
+ -1,
+ runCf.stderr.indexOf("Exception in thread \"main\" java.lang.NoSuchFieldError:"));
+ }
+
+ @Test
+ public void testDex() throws Exception {
+ ProcessResult runInput =
+ ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());
+ assertEquals(0, runInput.exitCode);
+ Path outDex = temp.getRoot().toPath().resolve("dex.zip");
+ build(new DexIndexedConsumer.ArchiveConsumer(outDex));
+ // TODO(b/76191597): Change to runArtNoVerificationErrors + assertEquals when bug is fixed
+ ProcessResult runDex = ToolHelper.runArtRaw(
+ outDex.toString(), CLASS.getCanonicalName());
+ assertNotEquals(runInput.stdout, runDex.stdout);
+ assertNotEquals(runInput.exitCode, runDex.exitCode);
+ assertNotEquals(
+ -1,
+ runDex.stderr.indexOf("Exception in thread \"main\" java.lang.NoSuchFieldError:"));
+ }
+
+ private void build(ProgramConsumer consumer) throws Exception {
+ List<String> config = Arrays.asList(
+ "-keep public class " + CLASS.getCanonicalName() + " {",
+ " public static void main(...);",
+ "}"
+ );
+ Builder builder = R8Command.builder()
+ .setMode(CompilationMode.DEBUG)
+ .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()))
+ .setProgramConsumer(consumer)
+ .addProguardConfiguration(config, Origin.unknown());
+ for (Class<?> c : CLASSES) {
+ builder.addClassProgramData(ToolHelper.getClassAsBytes(c), Origin.unknown());
+ }
+ if (consumer instanceof ClassFileConsumer) {
+ // TODO(b/75997473): Enable inlining when supported by CF.
+ ToolHelper.runR8(builder.build(), options -> options.enableInlining = false);
+ } else {
+ ToolHelper.runR8(builder.build());
+ }
+ }
+}