Merge commit '7a230461925d65a826100945f01a8b6f86ab3e66' into dev-release
Change-Id: Icae05d3e143368fcd9da4475dca8429568a1ae12
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 10f0699..cee4f28 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -152,12 +151,7 @@
DexString descriptor = annotationType.getDescriptor();
if (descriptor.startsWith(factory.dalvikAnnotationPrefix)) {
if (descriptor.startsWith(factory.dalvikAnnotationCodegenCovariantReturnTypePrefix)) {
- if (options.processCovariantReturnTypeAnnotations) {
- return true;
- }
- throw options.reporter.fatalError(
- new StringDiagnostic(
- "Unexpected @CovariantReturnType annotation in non-platform build"));
+ return options.processCovariantReturnTypeAnnotations;
}
return descriptor.startsWith(factory.dalvikAnnotationOptimizationPrefix);
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index adb0992..9ce000f 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -70,6 +70,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -649,14 +650,17 @@
private void dumpAndroidResourcesProvider(
AndroidResourceProvider androidResourceProvider, ZipOutputStream out, String name)
throws IOException, ResourceException {
+ Set<String> seen = new HashSet<>();
try (ByteArrayOutputStream archiveByteStream = new ByteArrayOutputStream()) {
try (ZipOutputStream archiveOutputStream = new ZipOutputStream(archiveByteStream)) {
for (AndroidResourceInput androidResource : androidResourceProvider.getAndroidResources()) {
- writeToZipStream(
- archiveOutputStream,
- androidResource.getPath().location(),
- androidResource.getByteStream().readAllBytes(),
- ZipEntry.DEFLATED);
+ if (seen.add(androidResource.getPath().location())) {
+ writeToZipStream(
+ archiveOutputStream,
+ androidResource.getPath().location(),
+ androidResource.getByteStream().readAllBytes(),
+ ZipEntry.DEFLATED);
+ }
}
}
writeToZipStream(out, name, archiveByteStream.toByteArray(), ZipEntry.DEFLATED);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java b/src/test/examplesJava17/records/RecordBlogTest.java
similarity index 84%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
rename to src/test/examplesJava17/records/RecordBlogTest.java
index 10f10f4..1128f07 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
+++ b/src/test/examplesJava17/records/RecordBlogTest.java
@@ -2,11 +2,12 @@
// 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.records;
+package records;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -26,9 +27,6 @@
@RunWith(Parameterized.class)
public class RecordBlogTest extends TestBase {
- private static final String RECORD_NAME = "RecordBlog";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
private static final String REFERENCE_OUTPUT_FORMAT = "Person[name=%s, age=42]";
private static final String CLASS = "records.RecordBlog$Person";
private static final Map<String, String> KEEP_RULE_TO_OUTPUT_FORMAT =
@@ -71,17 +69,17 @@
public void testReference() throws Exception {
assumeTrue(isCfRuntimeWithNativeRecordSupport());
testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addProgramClassesAndInnerClasses(RecordBlog.class)
+ .run(parameters.getRuntime(), RecordBlog.class)
.assertSuccessWithOutput(computeOutput(REFERENCE_OUTPUT_FORMAT));
}
@Test
public void testD8() throws Exception {
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addProgramClassesAndInnerClasses(RecordBlog.class)
.setMinApi(parameters)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordBlog.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -99,19 +97,19 @@
try {
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addProgramClassesAndInnerClasses(RecordBlog.class)
.setMinApi(parameters)
.addKeepRules(kr)
- .addKeepMainRule(MAIN_TYPE);
+ .addKeepMainRule(RecordBlog.class);
String res;
if (parameters.isCfRuntime()) {
res =
builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
+ .run(parameters.getRuntime(), RecordBlog.class)
.getStdOut();
} else {
- res = builder.run(parameters.getRuntime(), MAIN_TYPE).getStdOut();
+ res = builder.run(parameters.getRuntime(), RecordBlog.class).getStdOut();
}
results.put(kr, res);
} catch (Exception e) {
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java b/src/test/examplesJava17/records/RecordClasspathTest.java
similarity index 60%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java
rename to src/test/examplesJava17/records/RecordClasspathTest.java
index a431cf2..867d632 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordClasspathTest.java
+++ b/src/test/examplesJava17/records/RecordClasspathTest.java
@@ -2,21 +2,27 @@
// 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.records;
+package records;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.transformers.ClassFileTransformer.FieldPredicate;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
+import java.nio.file.Files;
import java.util.List;
import org.junit.Assume;
import org.junit.Test;
@@ -30,8 +36,6 @@
@RunWith(Parameterized.class)
public class RecordClasspathTest extends TestBase {
- private static final String RECORD_NAME_1 = "RecordWithMembers";
- private static final byte[][] PROGRAM_DATA_1 = RecordTestUtils.getProgramData(RECORD_NAME_1);
private static final String EXPECTED_RESULT = StringUtils.lines("Hello");
private final TestParameters parameters;
@@ -53,8 +57,19 @@
BooleanUtils.values());
}
- private byte[][] getClasspathData() {
- return stripClasspath ? stripFields(PROGRAM_DATA_1) : PROGRAM_DATA_1;
+ private byte[][] getClasspathData() throws IOException {
+ byte[][] programData =
+ ToolHelper.getClassFilesForInnerClasses(getClass()).stream()
+ .map(
+ c -> {
+ try {
+ return Files.readAllBytes(c);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .toArray(byte[][]::new);
+ return stripClasspath ? stripFields(programData) : programData;
}
private byte[][] stripFields(byte[][] programData1) {
@@ -80,6 +95,7 @@
public void testD8() throws Exception {
testForD8(parameters.getBackend())
.addProgramClasses(TestClass.class)
+ .addClasspathClasses(getClass())
.addClasspathClassFileData(getClasspathData())
.setMinApi(parameters)
.compile()
@@ -94,6 +110,7 @@
Assume.assumeFalse(parameters.isCfRuntime());
testForD8(parameters.getBackend())
.addProgramClasses(TestClass.class)
+ .addClasspathClasses(getClass())
.addClasspathClassFileData(getClasspathData())
.setMinApi(parameters)
.setIntermediate(true)
@@ -112,12 +129,20 @@
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class)
+ .addClasspathClassFileData(
+ TestBase.transformer(getClass())
+ .removeFields(FieldPredicate.all())
+ .removeMethods(MethodPredicate.all())
+ .removeAllAnnotations()
+ .setSuper(descriptor(Object.class))
+ .setImplements()
+ .transform())
.addClasspathClassFileData(getClasspathData())
.setMinApi(parameters)
.addKeepMainRule(TestClass.class);
if (parameters.isCfRuntime()) {
builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.inspect(this::assertNoRecord)
.inspect(RecordTestUtils::assertRecordsAreRecords)
@@ -140,4 +165,62 @@
System.out.println("Hello");
}
}
+
+ public class RecordWithMembers {
+
+ record PersonWithConstructors(String name, int age) {
+
+ public PersonWithConstructors(String name, int age) {
+ this.name = name + "X";
+ this.age = age;
+ }
+
+ public PersonWithConstructors(String name) {
+ this(name, -1);
+ }
+ }
+
+ record PersonWithMethods(String name, int age) {
+ public static void staticPrint() {
+ System.out.println("print");
+ }
+
+ @Override
+ public String toString() {
+ return name + age;
+ }
+ }
+
+ record PersonWithFields(String name, int age) {
+
+ // Extra instance fields are not allowed on records.
+ public static String globalName;
+ }
+
+ public static void main(String[] args) {
+ personWithConstructorTest();
+ personWithMethodsTest();
+ personWithFieldsTest();
+ }
+
+ private static void personWithConstructorTest() {
+ PersonWithConstructors bob = new PersonWithConstructors("Bob", 43);
+ System.out.println(bob.name());
+ System.out.println(bob.age());
+ PersonWithConstructors felix = new PersonWithConstructors("Felix");
+ System.out.println(felix.name());
+ System.out.println(felix.age());
+ }
+
+ private static void personWithMethodsTest() {
+ PersonWithMethods.staticPrint();
+ PersonWithMethods bob = new PersonWithMethods("Bob", 43);
+ System.out.println(bob.toString());
+ }
+
+ private static void personWithFieldsTest() {
+ PersonWithFields.globalName = "extra";
+ System.out.println(PersonWithFields.globalName);
+ }
+ }
}
diff --git a/src/test/examplesJava17/records/RecordComponentAnnotationsTest.java b/src/test/examplesJava17/records/RecordComponentAnnotationsTest.java
new file mode 100644
index 0000000..8aba71c
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordComponentAnnotationsTest.java
@@ -0,0 +1,476 @@
+// Copyright (c) 2023, 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 records;
+
+import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasAnnotationTypes;
+import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasElements;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.RecordComponent;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RecordComponentAnnotationsTest extends TestBase {
+
+ private static final String JVM_UNTIL_20_EXPECTED_RESULT =
+ StringUtils.lines(
+ "Jane Doe",
+ "42",
+ "true",
+ "2",
+ "name",
+ "java.lang.String",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"a\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(\"c\")",
+ "age",
+ "int",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"x\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(\"z\")",
+ "2",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"x\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(\"y\")",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"a\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(\"b\")");
+ private static final String JVM_FROM_21_EXPECTED_RESULT =
+ JVM_UNTIL_20_EXPECTED_RESULT.replaceAll(
+ "records.RecordComponentAnnotationsTest\\$Annotation",
+ "records.RecordComponentAnnotationsTest.Annotation");
+ private static final String ART_EXPECTED_RESULT =
+ StringUtils.lines(
+ "Jane Doe",
+ "42",
+ "true",
+ "2",
+ "name",
+ "java.lang.String",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=a)",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(value=c)",
+ "age",
+ "int",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=x)",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(value=z)",
+ "2",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=x)",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(value=y)",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=a)",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(value=b)");
+ private static final String JVM_EXPECTED_RESULT_R8 =
+ StringUtils.lines(
+ "Jane Doe",
+ "42",
+ "true",
+ "2",
+ "a",
+ "java.lang.String",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"a\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(\"c\")",
+ "b",
+ "int",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"x\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(\"z\")",
+ "2",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"a\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(\"b\")",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"x\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(\"y\")");
+ private static final String ART_EXPECTED_RESULT_R8 =
+ StringUtils.lines(
+ "Jane Doe",
+ "42",
+ "true",
+ "2",
+ "a",
+ "java.lang.String",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=a)",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(value=c)",
+ "b",
+ "int",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=x)",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(value=z)",
+ "2",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=a)",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(value=b)",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=x)",
+ "@records.RecordComponentAnnotationsTest$AnnotationFieldOnly(value=y)");
+ private static final String JVM_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS =
+ StringUtils.lines(
+ "Jane Doe",
+ "42",
+ "true",
+ "2",
+ "a",
+ "java.lang.String",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"a\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(\"c\")",
+ "b",
+ "int",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(\"x\")",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(\"z\")",
+ "2",
+ "0",
+ "0");
+ private static final String ART_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS =
+ StringUtils.lines(
+ "Jane Doe",
+ "42",
+ "true",
+ "2",
+ "a",
+ "java.lang.String",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=a)",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(value=c)",
+ "b",
+ "int",
+ "true",
+ "2",
+ "@records.RecordComponentAnnotationsTest$Annotation(value=x)",
+ "@records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly(value=z)",
+ "2",
+ "0",
+ "0");
+ private static final String EXPECTED_RESULT_DESUGARED_RECORD_SUPPORT =
+ StringUtils.lines("Jane Doe", "42", "false");
+ private static final String EXPECTED_RESULT_DESUGARED_NO_RECORD_SUPPORT =
+ StringUtils.lines("Jane Doe", "42", "Class.isRecord not present");
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public Boolean keepAnnotations;
+
+ // Enable once records are no longer partially desugared on platform.
+ public boolean recordDesugaringIsOffOnDex = false;
+
+ @Parameters(name = "{0}, keepAnnotations: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withDexRuntimesAndAllApiLevels()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+ .withAllApiLevelsAlsoForCf()
+ .build(),
+ BooleanUtils.values());
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeJvmTestParameters();
+ assumeTrue(keepAnnotations);
+ testForJvm(parameters)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordWithAnnotations.class)
+ .assertSuccessWithOutput(
+ parameters.getRuntime().asCf().getVm().isLessThanOrEqualTo(CfVm.JDK20)
+ ? JVM_UNTIL_20_EXPECTED_RESULT
+ : JVM_FROM_21_EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ parameters.assumeDexRuntime();
+ assumeTrue(keepAnnotations);
+ testForDesugaring(parameters)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordWithAnnotations.class)
+ .applyIf(
+ parameters.isDexRuntime(),
+ r ->
+ r.assertSuccessWithOutput(
+ runtimeWithRecordsSupport(parameters.getRuntime())
+ ? EXPECTED_RESULT_DESUGARED_RECORD_SUPPORT
+ : EXPECTED_RESULT_DESUGARED_NO_RECORD_SUPPORT),
+ r ->
+ r.assertSuccessWithOutput(ART_EXPECTED_RESULT)
+ .inspect(
+ inspector -> {
+ ClassSubject person =
+ inspector.clazz("records.RecordComponentAnnotationsTest$Person");
+ FieldSubject name = person.uniqueFieldWithOriginalName("name");
+ assertThat(name, isPresentAndNotRenamed());
+ FieldSubject age = person.uniqueFieldWithOriginalName("age");
+ assertThat(age, isPresentAndNotRenamed());
+ assertEquals(2, person.getFinalRecordComponents().size());
+
+ assertEquals(
+ name.getFinalName(),
+ person.getFinalRecordComponents().get(0).getName());
+ assertTrue(
+ person
+ .getFinalRecordComponents()
+ .get(0)
+ .getType()
+ .is("java.lang.String"));
+ assertNull(person.getFinalRecordComponents().get(0).getSignature());
+ assertEquals(
+ 2, person.getFinalRecordComponents().get(0).getAnnotations().size());
+ assertThat(
+ person.getFinalRecordComponents().get(0).getAnnotations(),
+ hasAnnotationTypes(
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$Annotation"),
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly")));
+ assertThat(
+ person.getFinalRecordComponents().get(0).getAnnotations().get(0),
+ hasElements(new Pair<>("value", "a")));
+ assertThat(
+ person.getFinalRecordComponents().get(0).getAnnotations().get(1),
+ hasElements(new Pair<>("value", "c")));
+
+ assertEquals(
+ age.getFinalName(),
+ person.getFinalRecordComponents().get(1).getName());
+ assertTrue(person.getFinalRecordComponents().get(1).getType().is("int"));
+ assertNull(person.getFinalRecordComponents().get(1).getSignature());
+ assertEquals(
+ 2, person.getFinalRecordComponents().get(1).getAnnotations().size());
+ assertThat(
+ person.getFinalRecordComponents().get(1).getAnnotations(),
+ hasAnnotationTypes(
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$Annotation"),
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly")));
+ assertThat(
+ person.getFinalRecordComponents().get(1).getAnnotations().get(0),
+ hasElements(new Pair<>("value", "x")));
+ assertThat(
+ person.getFinalRecordComponents().get(1).getAnnotations().get(1),
+ hasElements(new Pair<>("value", "z")));
+ }));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ parameters.assumeR8TestParameters();
+ testForR8(parameters.getBackend())
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addLibraryFiles(ToolHelper.getAndroidJar(35))
+ .addKeepMainRule(RecordWithAnnotations.class)
+ .addKeepClassAndMembersRulesWithAllowObfuscation(
+ "records.RecordComponentAnnotationsTest$Person")
+ .addKeepClassAndMembersRules(
+ "records.RecordComponentAnnotationsTest$Annotation",
+ "records.RecordComponentAnnotationsTest$AnnotationFieldOnly",
+ "records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly")
+ .applyIf(keepAnnotations, TestShrinkerBuilder::addKeepRuntimeVisibleAnnotations)
+ .setMinApi(parameters)
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject person =
+ inspector.clazz("records.RecordComponentAnnotationsTest$Person");
+ FieldSubject name = person.uniqueFieldWithOriginalName("name");
+ FieldSubject age = person.uniqueFieldWithOriginalName("age");
+ if (parameters.isCfRuntime()) {
+ assertEquals(2, person.getFinalRecordComponents().size());
+
+ assertEquals(
+ name.getFinalName(), person.getFinalRecordComponents().get(0).getName());
+ assertTrue(
+ person.getFinalRecordComponents().get(0).getType().is("java.lang.String"));
+ assertNull(person.getFinalRecordComponents().get(0).getSignature());
+ assertEquals(2, person.getFinalRecordComponents().get(0).getAnnotations().size());
+ assertThat(
+ person.getFinalRecordComponents().get(0).getAnnotations(),
+ hasAnnotationTypes(
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$Annotation"),
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly")));
+ assertThat(
+ person.getFinalRecordComponents().get(0).getAnnotations().get(0),
+ hasElements(new Pair<>("value", "a")));
+ assertThat(
+ person.getFinalRecordComponents().get(0).getAnnotations().get(1),
+ hasElements(new Pair<>("value", "c")));
+
+ assertEquals(
+ age.getFinalName(), person.getFinalRecordComponents().get(1).getName());
+ assertTrue(person.getFinalRecordComponents().get(1).getType().is("int"));
+ assertNull(person.getFinalRecordComponents().get(1).getSignature());
+ assertEquals(2, person.getFinalRecordComponents().get(1).getAnnotations().size());
+ assertThat(
+ person.getFinalRecordComponents().get(1).getAnnotations(),
+ hasAnnotationTypes(
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$Annotation"),
+ inspector.getTypeSubject(
+ "records.RecordComponentAnnotationsTest$AnnotationRecordComponentOnly")));
+ assertThat(
+ person.getFinalRecordComponents().get(1).getAnnotations().get(0),
+ hasElements(new Pair<>("value", "x")));
+ assertThat(
+ person.getFinalRecordComponents().get(1).getAnnotations().get(1),
+ hasElements(new Pair<>("value", "z")));
+ } else {
+ assertEquals(0, person.getFinalRecordComponents().size());
+ }
+ })
+ .run(parameters.getRuntime(), RecordWithAnnotations.class)
+ .applyIf(
+ // TODO(b/274888318): EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS still has component
+ // annotations.
+ parameters.isCfRuntime(),
+ r ->
+ r.assertSuccessWithOutput(
+ keepAnnotations
+ ? JVM_EXPECTED_RESULT_R8
+ : JVM_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS),
+ recordDesugaringIsOffOnDex,
+ r ->
+ r.assertSuccessWithOutput(
+ keepAnnotations
+ ? ART_EXPECTED_RESULT_R8
+ : ART_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS),
+ r ->
+ r.assertSuccessWithOutput(
+ runtimeWithRecordsSupport(parameters.getRuntime())
+ ? EXPECTED_RESULT_DESUGARED_RECORD_SUPPORT
+ : EXPECTED_RESULT_DESUGARED_NO_RECORD_SUPPORT));
+ }
+
+ @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Annotation {
+
+ String value();
+ }
+
+ @Target(ElementType.FIELD)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface AnnotationFieldOnly {
+
+ String value();
+ }
+
+ @Target(ElementType.RECORD_COMPONENT)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface AnnotationRecordComponentOnly {
+
+ String value();
+ }
+
+ record Person(
+ @Annotation("a") @AnnotationFieldOnly("b") @AnnotationRecordComponentOnly("c") String name,
+ @Annotation("x") @AnnotationFieldOnly("y") @AnnotationRecordComponentOnly("z") int age) {}
+
+ public static class RecordWithAnnotations {
+
+ public static void main(String[] args) {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.name());
+ System.out.println(janeDoe.age());
+ try {
+ Class.class.getDeclaredMethod("isRecord");
+ } catch (NoSuchMethodException e) {
+ System.out.println("Class.isRecord not present");
+ return;
+ }
+ System.out.println(Person.class.isRecord());
+ if (Person.class.isRecord()) {
+ System.out.println(Person.class.getRecordComponents().length);
+ for (int i = 0; i < Person.class.getRecordComponents().length; i++) {
+ RecordComponent c = Person.class.getRecordComponents()[i];
+ System.out.println(c.getName());
+ System.out.println(c.getType().getName());
+ System.out.println(c.getGenericSignature() == null);
+ System.out.println(c.getAnnotations().length);
+ // Collect and sort the annotations, as the order is not deterministic on Art (tested
+ // on Art 14 Beta 3).
+ List<String> annotations = new ArrayList<>();
+ for (int j = 0; j < c.getAnnotations().length; j++) {
+ annotations.add(c.getAnnotations()[j].toString());
+ }
+ annotations.sort(Comparator.naturalOrder());
+ for (int j = 0; j < annotations.size(); j++) {
+ System.out.println(annotations.get(j));
+ }
+ }
+ System.out.println(Person.class.getDeclaredFields().length);
+ List<Field> fields = new ArrayList<>();
+ for (int i = 0; i < Person.class.getDeclaredFields().length; i++) {
+ fields.add(Person.class.getDeclaredFields()[i]);
+ }
+ fields.sort(
+ new Comparator<Field>() {
+ @Override
+ public int compare(Field o1, Field o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+ for (int i = 0; i < fields.size(); i++) {
+ Field f = fields.get(i);
+ System.out.println(f.getDeclaredAnnotations().length);
+ List<String> annotations = new ArrayList<>();
+ for (int j = 0; j < f.getDeclaredAnnotations().length; j++) {
+ annotations.add(f.getAnnotations()[j].toString());
+ }
+ annotations.sort(Comparator.naturalOrder());
+ for (int j = 0; j < annotations.size(); j++) {
+ System.out.println(annotations.get(j));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java b/src/test/examplesJava17/records/RecordComponentSignatureTest.java
similarity index 74%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
rename to src/test/examplesJava17/records/RecordComponentSignatureTest.java
index 27e7e0b..d2d530b 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
+++ b/src/test/examplesJava17/records/RecordComponentSignatureTest.java
@@ -1,7 +1,7 @@
// Copyright (c) 2023, 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.records;
+package records;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -13,10 +13,12 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import java.lang.reflect.RecordComponent;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -27,15 +29,10 @@
@RunWith(Parameterized.class)
public class RecordComponentSignatureTest extends TestBase {
- private static final String RECORD_NAME = "RecordWithSignature";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
private static final String EXPECTED_RESULT =
StringUtils.lines(
"Jane Doe",
"42",
- "Jane Doe",
- "42",
"true",
"2",
"name",
@@ -46,12 +43,11 @@
"java.lang.Object",
"TA;",
"0");
- private static final String EXPECTED_RESULT_R8 =
- StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "true", "0");
+ private static final String EXPECTED_RESULT_R8 = StringUtils.lines("Jane Doe", "42", "true", "0");
private static final String EXPECTED_RESULT_DESUGARED_NO_NATIVE_RECORDS_SUPPORT =
- StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "Class.isRecord not present");
+ StringUtils.lines("Jane Doe", "42", "Class.isRecord not present");
private static final String EXPECTED_RESULT_DESUGARED_NATIVE_RECORD_SUPPORT =
- StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "false");
+ StringUtils.lines("Jane Doe", "42", "false");
@Parameter(0)
public TestParameters parameters;
@@ -75,8 +71,8 @@
parameters.assumeJvmTestParameters();
assumeTrue(keepSignatures);
testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordWithSignature.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -85,8 +81,8 @@
parameters.assumeDexRuntime();
assumeTrue(keepSignatures);
testForDesugaring(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordWithSignature.class)
.applyIf(
parameters.isCfRuntime(),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
@@ -98,7 +94,7 @@
.inspect(
inspector -> {
ClassSubject person =
- inspector.clazz("records.RecordWithSignature$Person");
+ inspector.clazz("records.RecordComponentSignatureTest$Person");
if (parameters.isCfRuntime()) {
assertEquals(2, person.getFinalRecordComponents().size());
@@ -138,22 +134,20 @@
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- // TODO(b/231930852): Change to android.jar for Android U when that contains
- // java.lang.Record.
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addKeepMainRule(MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addLibraryFiles(ToolHelper.getAndroidJar(35))
+ .addKeepMainRule(RecordWithSignature.class)
.applyIf(keepSignatures, TestShrinkerBuilder::addKeepAttributeSignature)
.setMinApi(parameters)
.compile()
.inspect(
inspector -> {
- ClassSubject person = inspector.clazz("records.RecordWithSignature$Person");
+ ClassSubject person = inspector.clazz("records.RecordComponentSignatureTest$Person");
FieldSubject age = person.uniqueFieldWithOriginalName("age");
assertThat(age, isAbsent());
assertEquals(0, person.getFinalRecordComponents().size());
})
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordWithSignature.class)
.applyIf(
runtimeWithRecordsSupport(parameters.getRuntime()),
r ->
@@ -163,4 +157,32 @@
: EXPECTED_RESULT_R8),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED_NO_NATIVE_RECORDS_SUPPORT));
}
+
+ record Person<N extends CharSequence, A>(N name, A age) {}
+
+ public class RecordWithSignature {
+
+ public static void main(String[] args) {
+ Person<String, Integer> janeDoe = new Person<>("Jane Doe", 42);
+ System.out.println(janeDoe.name());
+ System.out.println(janeDoe.age());
+ try {
+ Class.class.getDeclaredMethod("isRecord");
+ } catch (NoSuchMethodException e) {
+ System.out.println("Class.isRecord not present");
+ return;
+ }
+ System.out.println(Person.class.isRecord());
+ if (Person.class.isRecord()) {
+ System.out.println(Person.class.getRecordComponents().length);
+ for (int i = 0; i < Person.class.getRecordComponents().length; i++) {
+ RecordComponent c = Person.class.getRecordComponents()[i];
+ System.out.println(c.getName());
+ System.out.println(c.getType().getName());
+ System.out.println(c.getGenericSignature());
+ System.out.println(c.getAnnotations().length);
+ }
+ }
+ }
+ }
}
diff --git a/src/test/examplesJava17/records/RecordInterface.java b/src/test/examplesJava17/records/RecordInterface.java
deleted file mode 100644
index 8fc1e56..0000000
--- a/src/test/examplesJava17/records/RecordInterface.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2023, 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 records;
-
-public class RecordInterface {
-
- interface Human {
- default void printHuman() {
- System.out.println("Human");
- }
- }
-
- record Person(String name, int age) implements Human {}
-
- public static void main(String[] args) {
- Person janeDoe = new Person("Jane Doe", 42);
- janeDoe.printHuman();
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java b/src/test/examplesJava17/records/RecordInterfaceTest.java
similarity index 74%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
rename to src/test/examplesJava17/records/RecordInterfaceTest.java
index 169ef16..d5144b0 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
+++ b/src/test/examplesJava17/records/RecordInterfaceTest.java
@@ -2,26 +2,31 @@
// 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.records;
+package records;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.GlobalSyntheticsConsumer;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.desugar.graph.DesugarGraphTestConsumer;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,9 +36,6 @@
@RunWith(Parameterized.class)
public class RecordInterfaceTest extends TestBase {
- private static final String RECORD_NAME = "RecordInterface";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
private static final String EXPECTED_RESULT = StringUtils.lines("Human");
@Parameter(0)
@@ -54,17 +56,17 @@
public void testReference() throws Exception {
assumeTrue(isCfRuntimeWithNativeRecordSupport());
testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordInterface.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@Test
public void testD8() throws Exception {
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordInterface.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -91,7 +93,7 @@
.setIncludeClassesChecksum(true)
.compile()
.assertNoMessages()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordInterface.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
assertNoEdgeToRecord(consumer);
}
@@ -117,7 +119,7 @@
.disableDesugaring()
.compile()
.assertNoMessages()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordInterface.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
assertNoEdgeToRecord(consumer);
}
@@ -128,12 +130,16 @@
DesugarGraphTestConsumer consumer = new DesugarGraphTestConsumer();
Path intermediate =
testForD8(Backend.DEX)
+ .addStrippedOuter(getClass(), fake)
.apply(
b -> {
- // We avoid unknown origin here since they are not allowed when using a Graph
- // consumer.
- for (byte[] programDatum : PROGRAM_DATA) {
- b.getBuilder().addClassProgramData(programDatum, fake);
+ try {
+ for (Path file :
+ ToolHelper.getClassFilesForInnerClasses(ImmutableList.of(getClass()))) {
+ b.getBuilder().addClassProgramData(Files.readAllBytes(file), fake);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
})
.setMinApi(parameters)
@@ -149,7 +155,7 @@
}
private void assertNoEdgeToRecord(DesugarGraphTestConsumer consumer) {
- assertEquals(0, consumer.totalEdgeCount());
+ Assert.assertEquals(0, consumer.totalEdgeCount());
}
@Test
@@ -158,18 +164,37 @@
assumeTrue(parameters.isDexRuntime() || isCfRuntimeWithNativeRecordSupport());
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE);
+ .addKeepMainRule(RecordInterface.class);
if (parameters.isCfRuntime()) {
builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.inspect(RecordTestUtils::assertRecordsAreRecords)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordInterface.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
return;
}
- builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT);
+ builder
+ .run(parameters.getRuntime(), RecordInterface.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ interface Human {
+
+ default void printHuman() {
+ System.out.println("Human");
+ }
+ }
+
+ record Person(String name, int age) implements Human {}
+
+ public class RecordInterface {
+
+ public static void main(String[] args) {
+ Person janeDoe = new Person("Jane Doe", 42);
+ janeDoe.printHuman();
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java b/src/test/examplesJava17/records/RecordInvokeCustomSplitDesugaringTest.java
similarity index 67%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
rename to src/test/examplesJava17/records/RecordInvokeCustomSplitDesugaringTest.java
index b782568..d797244 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
+++ b/src/test/examplesJava17/records/RecordInvokeCustomSplitDesugaringTest.java
@@ -2,7 +2,7 @@
// 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.records;
+package records;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
@@ -25,13 +25,12 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import records.RecordInvokeCustom.Empty;
+import records.RecordInvokeCustom.Person;
@RunWith(Parameterized.class)
public class RecordInvokeCustomSplitDesugaringTest extends TestBase {
- private static final String RECORD_NAME = "RecordInvokeCustom";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
private static final String EXPECTED_RESULT =
StringUtils.lines(
"%s[]",
@@ -64,7 +63,7 @@
public void testD8() throws Exception {
Path desugared =
testForD8(Backend.CF)
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.compile()
.writeToZip();
@@ -72,7 +71,7 @@
.addProgramFiles(desugared)
.setMinApi(parameters)
.compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordInvokeCustom.class)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
}
@@ -81,7 +80,7 @@
parameters.assumeR8TestParameters();
Path desugared =
testForD8(Backend.CF)
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.compile()
.writeToZip();
@@ -94,7 +93,7 @@
testForR8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE)
+ .addKeepMainRule(RecordInvokeCustom.class)
.allowDiagnosticMessages()
.compileWithExpectedDiagnostics(
// Class com.android.tools.r8.RecordTag in desugared input is seen as java.lang.Record
@@ -119,10 +118,12 @@
})
.inspect(
i -> {
- minifiedNames[0] = extractSimpleFinalName(i, "records.RecordInvokeCustom$Empty");
- minifiedNames[1] = extractSimpleFinalName(i, "records.RecordInvokeCustom$Person");
+ minifiedNames[0] =
+ extractSimpleFinalName(i, "records.RecordInvokeCustomSplitDesugaringTest$Empty");
+ minifiedNames[1] =
+ extractSimpleFinalName(i, "records.RecordInvokeCustomSplitDesugaringTest$Person");
})
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordInvokeCustom.class)
.assertSuccessWithOutput(
String.format(EXPECTED_RESULT, minifiedNames[0], minifiedNames[1]));
}
@@ -131,4 +132,47 @@
String finalName = i.clazz(name).getFinalName();
return finalName.split("\\.")[1];
}
+
+ record Empty() {}
+
+ record Person(String name, int age) {}
+
+ public class RecordInvokeCustom {
+
+ public static void main(String[] args) {
+ emptyTest();
+ equalityTest();
+ toStringTest();
+ }
+
+ private static void emptyTest() {
+ Empty empty1 = new Empty();
+ Empty empty2 = new Empty();
+ System.out.println(empty1.toString());
+ System.out.println(empty1.equals(empty2));
+ System.out.println(empty1.hashCode() == empty2.hashCode());
+ System.out.println(empty1.toString().equals(empty2.toString()));
+ }
+
+ private static void toStringTest() {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.toString());
+ }
+
+ private static void equalityTest() {
+ Person jane1 = new Person("Jane Doe", 42);
+ Person jane2 = new Person("Jane Doe", 42);
+ String nonIdenticalString = "Jane " + (System.currentTimeMillis() > 0 ? "Doe" : "Zan");
+ Person jane3 = new Person(nonIdenticalString, 42);
+ Person bob = new Person("Bob", 42);
+ Person youngJane = new Person("Jane Doe", 22);
+ System.out.println(jane1.equals(jane2));
+ System.out.println(jane1.toString().equals(jane2.toString()));
+ System.out.println(nonIdenticalString == "Jane Doe"); // false.
+ System.out.println(nonIdenticalString.equals("Jane Doe")); // true.
+ System.out.println(jane1.equals(jane3));
+ System.out.println(jane1.equals(bob));
+ System.out.println(jane1.equals(youngJane));
+ }
+ }
}
diff --git a/src/test/examplesJava17/records/RecordInvokeCustomTest.java b/src/test/examplesJava17/records/RecordInvokeCustomTest.java
new file mode 100644
index 0000000..ec3956a
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordInvokeCustomTest.java
@@ -0,0 +1,140 @@
+// Copyright (c) 2021, 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 records;
+
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.LibraryFilesHelper;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import records.RecordInvokeCustom.Empty;
+import records.RecordInvokeCustom.Person;
+
+@RunWith(Parameterized.class)
+public class RecordInvokeCustomTest extends TestBase {
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "%s[]",
+ "true",
+ "true",
+ "true",
+ "true",
+ "true",
+ "false",
+ "true",
+ "true",
+ "false",
+ "false",
+ "%s[%s=Jane Doe, %s=42]");
+ private static final String EXPECTED_RESULT_D8 =
+ String.format(EXPECTED_RESULT, "Empty", "Person", "name", "age");
+ private static final String EXPECTED_RESULT_R8 =
+ String.format(EXPECTED_RESULT, "a", "b", "a", "b");
+
+ private final TestParameters parameters;
+
+ public RecordInvokeCustomTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+ .withDexRuntimes()
+ .withAllApiLevelsAlsoForCf()
+ .build();
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeJvmTestParameters();
+ testForJvm(parameters)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordInvokeCustom.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT_D8);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addInnerClassesAndStrippedOuter(getClass())
+ .setMinApi(parameters)
+ .compile()
+ .run(parameters.getRuntime(), RecordInvokeCustom.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT_D8);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ parameters.assumeR8TestParameters();
+ R8FullTestBuilder builder =
+ testForR8(parameters.getBackend())
+ .addInnerClassesAndStrippedOuter(getClass())
+ .setMinApi(parameters)
+ .addKeepMainRule(RecordInvokeCustom.class);
+ if (parameters.isCfRuntime()) {
+ builder
+ .addLibraryFiles(LibraryFilesHelper.getJdk15LibraryFiles(temp))
+ .compile()
+ .inspect(RecordTestUtils::assertRecordsAreRecords)
+ .run(parameters.getRuntime(), RecordInvokeCustom.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+ return;
+ }
+ builder
+ .run(parameters.getRuntime(), RecordInvokeCustom.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+ }
+
+ record Empty() {}
+
+ record Person(String name, int age) {}
+
+ public class RecordInvokeCustom {
+
+ public static void main(String[] args) {
+ emptyTest();
+ equalityTest();
+ toStringTest();
+ }
+
+ private static void emptyTest() {
+ Empty empty1 = new Empty();
+ Empty empty2 = new Empty();
+ System.out.println(empty1.toString());
+ System.out.println(empty1.equals(empty2));
+ System.out.println(empty1.hashCode() == empty2.hashCode());
+ System.out.println(empty1.toString().equals(empty2.toString()));
+ }
+
+ private static void toStringTest() {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.toString());
+ }
+
+ private static void equalityTest() {
+ Person jane1 = new Person("Jane Doe", 42);
+ Person jane2 = new Person("Jane Doe", 42);
+ String nonIdenticalString = "Jane " + (System.currentTimeMillis() > 0 ? "Doe" : "Zan");
+ Person jane3 = new Person(nonIdenticalString, 42);
+ Person bob = new Person("Bob", 42);
+ Person youngJane = new Person("Jane Doe", 22);
+ System.out.println(jane1.equals(jane2));
+ System.out.println(jane1.toString().equals(jane2.toString()));
+ System.out.println(nonIdenticalString == "Jane Doe"); // false.
+ System.out.println(nonIdenticalString.equals("Jane Doe")); // true.
+ System.out.println(jane1.equals(jane3));
+ System.out.println(jane1.equals(bob));
+ System.out.println(jane1.equals(youngJane));
+ }
+ }
+}
diff --git a/src/test/examplesJava17/records/RecordShrinkField.java b/src/test/examplesJava17/records/RecordKeepRules.java
similarity index 73%
rename from src/test/examplesJava17/records/RecordShrinkField.java
rename to src/test/examplesJava17/records/RecordKeepRules.java
index 2a21904..a62132f 100644
--- a/src/test/examplesJava17/records/RecordShrinkField.java
+++ b/src/test/examplesJava17/records/RecordKeepRules.java
@@ -4,7 +4,9 @@
package records;
-public class RecordShrinkField {
+// The code needs to be completely outside the test for the test to work.
+// If these classes are inner classes, age is not correctly simplified to a 42 constant field.
+public class RecordKeepRules {
record Person(int unused, String name, int age) {
Person(String name, int age) {
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java b/src/test/examplesJava17/records/RecordKeepRulesTest.java
similarity index 76%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java
rename to src/test/examplesJava17/records/RecordKeepRulesTest.java
index 68c85df..cf864fe 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java
+++ b/src/test/examplesJava17/records/RecordKeepRulesTest.java
@@ -2,8 +2,9 @@
// 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.records;
+package records;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -17,30 +18,26 @@
@RunWith(Parameterized.class)
public class RecordKeepRulesTest extends TestBase {
- private static final String RECORD_NAME = "RecordShrinkField";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
-
private static final String KEEP_RULE_CLASS_NAME =
- "-keep,allowshrinking,allowoptimization class records.RecordShrinkField$Person";
+ "-keep,allowshrinking,allowoptimization class records.RecordKeepRules$Person";
private static final String KEEP_RULE_FIELD_NAMES =
- "-keepclassmembers,allowshrinking,allowoptimization class records.RecordShrinkField$Person {"
+ "-keepclassmembers,allowshrinking,allowoptimization class records.RecordKeepRules$Person {"
+ " <fields>; }";
private static final String KEEP_RULE_FIELDS_NO_NAMES =
- "-keepclassmembers,allowobfuscation class records.RecordShrinkField$Person { <fields>; }";
+ "-keepclassmembers,allowobfuscation class records.RecordKeepRules$Person { <fields>; }";
private static final String KEEP_RULE_ALL =
- "-keep class records.RecordShrinkField$Person { <fields>; }";
+ "-keep class records.RecordKeepRules$Person { <fields>; }";
private static final String EXPECTED_RESULT_R8_WITH_CLASS_NAME =
- StringUtils.lines("RecordShrinkField$Person[a=Jane Doe]", "RecordShrinkField$Person[a=Bob]");
+ StringUtils.lines("RecordKeepRules$Person[a=Jane Doe]", "RecordKeepRules$Person[a=Bob]");
private static final String EXPECTED_RESULT_R8_WITH_FIELD_NAMES =
StringUtils.lines("a[name=Jane Doe]", "a[name=Bob]");
private static final String EXPECTED_RESULT_R8_WITH_FIELD_NO_NAMES =
StringUtils.lines("a[a=-1, b=Jane Doe, c=42]", "a[a=-1, b=Bob, c=42]");
private static final String EXPECTED_RESULT_R8_WITH_ALL =
StringUtils.lines(
- "RecordShrinkField$Person[unused=-1, name=Jane Doe, age=42]",
- "RecordShrinkField$Person[unused=-1, name=Bob, age=42]");
+ "RecordKeepRules$Person[unused=-1, name=Jane Doe, age=42]",
+ "RecordKeepRules$Person[unused=-1, name=Bob, age=42]");
private final TestParameters parameters;
private final boolean proguardCompatibility;
@@ -82,27 +79,27 @@
private void testR8FieldNames(String keepRules, String expectedOutput) throws Exception {
testForR8Compat(parameters.getBackend(), proguardCompatibility)
- .addProgramClassFileData(PROGRAM_DATA)
+ .addProgramClassesAndInnerClasses(RecordKeepRules.class)
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE)
+ .addKeepMainRule(RecordKeepRules.class)
.addKeepRules(keepRules)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordKeepRules.class)
.assertSuccessWithOutput(expectedOutput);
}
private void testR8CfThenDexFieldNames(String keepRules, String expectedOutput) throws Exception {
Path desugared =
testForR8Compat(Backend.CF, proguardCompatibility)
- .addProgramClassFileData(PROGRAM_DATA)
- .addKeepMainRule(MAIN_TYPE)
+ .addProgramClassesAndInnerClasses(RecordKeepRules.class)
+ .addKeepMainRule(RecordKeepRules.class)
.addKeepRules(keepRules)
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.writeToZip();
testForD8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordKeepRules.class)
.assertSuccessWithOutput(expectedOutput);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java b/src/test/examplesJava17/records/RecordLibMergeTest.java
similarity index 70%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
rename to src/test/examplesJava17/records/RecordLibMergeTest.java
index ca7a7b5..fd0e655 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
+++ b/src/test/examplesJava17/records/RecordLibMergeTest.java
@@ -2,8 +2,9 @@
// 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.records;
+package records;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -18,11 +19,6 @@
@RunWith(Parameterized.class)
public class RecordLibMergeTest extends TestBase {
- private static final String RECORD_LIB = "RecordLib";
- private static final String RECORD_MAIN = "RecordMain";
- private static final byte[][] PROGRAM_DATA_LIB = RecordTestUtils.getProgramData(RECORD_LIB);
- private static final byte[][] PROGRAM_DATA_MAIN = RecordTestUtils.getProgramData(RECORD_MAIN);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_MAIN);
private static final String EXPECTED_RESULT = StringUtils.lines("true", "true");
private final TestParameters parameters;
@@ -45,30 +41,30 @@
parameters.assumeR8TestParameters();
Path lib =
testForR8(Backend.CF)
- .addProgramClassFileData(PROGRAM_DATA_LIB)
+ .addProgramClassesAndInnerClasses(RecordLib.class)
.addKeepRules(
"-keep class records.RecordLib { public static java.lang.Object getRecord(); }")
.addKeepRules("-keep class records.RecordLib$LibRecord")
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.writeToZip();
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
.addProgramFiles(lib)
- .addProgramClassFileData(PROGRAM_DATA_MAIN)
+ .addProgramClassesAndInnerClasses(RecordMain.class)
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE)
+ .addKeepMainRule(RecordMain.class)
.addKeepRules("-keep class records.RecordLib$LibRecord")
.addKeepRules("-keep class records.RecordMain$MainRecord");
if (parameters.isCfRuntime()) {
builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.inspect(RecordTestUtils::assertRecordsAreRecords)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordMain.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
return;
}
- builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT);
+ builder.run(parameters.getRuntime(), RecordMain.class).assertSuccessWithOutput(EXPECTED_RESULT);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/examplesJava17/records/RecordMergeTest.java
similarity index 67%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
rename to src/test/examplesJava17/records/RecordMergeTest.java
index d05a57a..4153e38 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
+++ b/src/test/examplesJava17/records/RecordMergeTest.java
@@ -2,7 +2,7 @@
// 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.records;
+package records;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
@@ -14,13 +14,13 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestBuilder;
import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
@@ -32,29 +32,12 @@
@RunWith(Parameterized.class)
public class RecordMergeTest extends TestBase {
- private static final String RECORD_NAME_1 = "RecordWithMembers";
- private static final byte[][] PROGRAM_DATA_1 = RecordTestUtils.getProgramData(RECORD_NAME_1);
- private static final String MAIN_TYPE_1 = RecordTestUtils.getMainType(RECORD_NAME_1);
private static final String EXPECTED_RESULT_1 =
- StringUtils.lines(
- "BobX", "43", "BobX", "43", "FelixX", "-1", "FelixX", "-1", "print", "Bob43", "extra");
+ StringUtils.lines("BobX", "43", "FelixX", "-1", "print", "Bob43", "extra");
- private static final String RECORD_NAME_2 = "SimpleRecord";
- private static final byte[][] PROGRAM_DATA_2 = RecordTestUtils.getProgramData(RECORD_NAME_2);
- private static final String MAIN_TYPE_2 = RecordTestUtils.getMainType(RECORD_NAME_2);
private static final String EXPECTED_RESULT_2 =
StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "true",
- "true",
- "false",
- "false",
- "false",
- "false");
+ "Jane Doe", "42", "true", "true", "true", "false", "false", "false", "false");
private final TestParameters parameters;
@@ -71,7 +54,9 @@
public void testNoGlobalSyntheticsConsumer() throws Exception {
D8TestBuilder builder =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA_1)
+ .addStrippedOuter(getClass())
+ .addProgramClassesAndInnerClasses(RecordWithMembers.class)
+ .addClasspathClassesAndInnerClasses(SimpleRecord.class)
.setMinApi(parameters)
.setIntermediate(true);
if (isRecordsFullyDesugaredForD8(parameters)) {
@@ -104,7 +89,9 @@
GlobalSyntheticsTestingConsumer globals1 = new GlobalSyntheticsTestingConsumer();
Path output1 =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA_1)
+ .addStrippedOuter(getClass())
+ .addProgramClassesAndInnerClasses(RecordWithMembers.class)
+ .addClasspathClassesAndInnerClasses(SimpleRecord.class)
.setMinApi(parameters)
.setIntermediate(true)
.applyIf(
@@ -118,7 +105,8 @@
GlobalSyntheticsTestingConsumer globals2 = new GlobalSyntheticsTestingConsumer();
Path output2 =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA_2)
+ .addProgramClassesAndInnerClasses(SimpleRecord.class)
+ .addClasspathClassesAndInnerClasses(getClass())
.setMinApi(parameters)
.setIntermediate(true)
.applyIf(
@@ -145,14 +133,14 @@
.inspect(this::assertHasRecordTag);
result
- .run(parameters.getRuntime(), MAIN_TYPE_1)
+ .run(parameters.getRuntime(), RecordWithMembers.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_1),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
result
- .run(parameters.getRuntime(), MAIN_TYPE_2)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -165,7 +153,9 @@
GlobalSyntheticsTestingConsumer globals1 = new GlobalSyntheticsTestingConsumer();
Path output1 =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA_1)
+ .addProgramClassesAndInnerClasses(RecordWithMembers.class)
+ .addClasspathClasses(getClass())
+ .addClasspathClassesAndInnerClasses(SimpleRecord.class)
.setMinApi(parameters)
.setIntermediate(true)
.apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals1))
@@ -174,21 +164,23 @@
D8TestCompileResult result =
testForD8(parameters.getBackend())
+ .addStrippedOuter(getClass())
.addProgramFiles(output1)
.apply(
b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals1.getProviders()))
- .addProgramClassFileData(PROGRAM_DATA_2)
+ .addProgramClassesAndInnerClasses(SimpleRecord.class)
+ .addClasspathClassesAndInnerClasses(getClass())
.setMinApi(parameters)
.compile();
result
- .run(parameters.getRuntime(), MAIN_TYPE_1)
+ .run(parameters.getRuntime(), RecordWithMembers.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_1),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
result
- .run(parameters.getRuntime(), MAIN_TYPE_2)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -200,7 +192,9 @@
public void testMergeNonIntermediates() throws Exception {
Path output1 =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA_1)
+ .addStrippedOuter(getClass())
+ .addProgramClassesAndInnerClasses(RecordWithMembers.class)
+ .addClasspathClassesAndInnerClasses(SimpleRecord.class)
.setMinApi(parameters)
.compile()
.inspect(this::assertHasRecordTag)
@@ -208,7 +202,8 @@
Path output2 =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA_2)
+ .addProgramClassesAndInnerClasses(SimpleRecord.class)
+ .addClasspathClassesAndInnerClasses(getClass())
.setMinApi(parameters)
.compile()
.inspect(this::assertHasRecordTag)
@@ -221,14 +216,14 @@
.setMinApi(parameters)
.compile();
result
- .run(parameters.getRuntime(), MAIN_TYPE_1)
+ .run(parameters.getRuntime(), RecordWithMembers.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_1),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
result
- .run(parameters.getRuntime(), MAIN_TYPE_2)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -259,4 +254,89 @@
// Note: this should be asserting on record tag.
assertThat(inspector.clazz("java.lang.Record"), isAbsent());
}
+
+ public class RecordWithMembers {
+ record PersonWithConstructors(String name, int age) {
+
+ public PersonWithConstructors(String name, int age) {
+ this.name = name + "X";
+ this.age = age;
+ }
+
+ public PersonWithConstructors(String name) {
+ this(name, -1);
+ }
+ }
+
+ record PersonWithMethods(String name, int age) {
+ public static void staticPrint() {
+ System.out.println("print");
+ }
+
+ @Override
+ public String toString() {
+ return name + age;
+ }
+ }
+
+ record PersonWithFields(String name, int age) {
+
+ // Extra instance fields are not allowed on records.
+ public static String globalName;
+ }
+
+ public static void main(String[] args) {
+ personWithConstructorTest();
+ personWithMethodsTest();
+ personWithFieldsTest();
+ }
+
+ private static void personWithConstructorTest() {
+ PersonWithConstructors bob = new PersonWithConstructors("Bob", 43);
+ System.out.println(bob.name());
+ System.out.println(bob.age());
+ PersonWithConstructors felix = new PersonWithConstructors("Felix");
+ System.out.println(felix.name());
+ System.out.println(felix.age());
+ }
+
+ private static void personWithMethodsTest() {
+ PersonWithMethods.staticPrint();
+ PersonWithMethods bob = new PersonWithMethods("Bob", 43);
+ System.out.println(bob.toString());
+ }
+
+ private static void personWithFieldsTest() {
+ PersonWithFields.globalName = "extra";
+ System.out.println(PersonWithFields.globalName);
+ }
+ }
+
+ public class SimpleRecord {
+
+ record Person(String name, int age) {}
+
+ public static void main(String[] args) {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.name());
+ System.out.println(janeDoe.age());
+
+ // Test equals with self.
+ System.out.println(janeDoe.equals(janeDoe));
+
+ // Test equals with structurally equals Person.
+ Person otherJaneDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.equals(otherJaneDoe));
+ System.out.println(otherJaneDoe.equals(janeDoe));
+
+ // Test equals with not-structually equals Person.
+ Person johnDoe = new Person("John Doe", 42);
+ System.out.println(janeDoe.equals(johnDoe));
+ System.out.println(johnDoe.equals(janeDoe));
+
+ // Test equals with Object and null.
+ System.out.println(janeDoe.equals(new Object()));
+ System.out.println(janeDoe.equals(null));
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java b/src/test/examplesJava17/records/RecordProfileRewritingTest.java
similarity index 86%
rename from src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
rename to src/test/examplesJava17/records/RecordProfileRewritingTest.java
index 602cdfc..13c5b5a 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
+++ b/src/test/examplesJava17/records/RecordProfileRewritingTest.java
@@ -2,7 +2,7 @@
// 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.profile.art.completeness;
+package records;
import static com.android.tools.r8.ir.desugar.records.RecordFullInstructionDesugaring.EQUALS_RECORD_METHOD_NAME;
import static com.android.tools.r8.ir.desugar.records.RecordFullInstructionDesugaring.GET_FIELDS_AS_OBJECTS_METHOD_NAME;
@@ -16,11 +16,11 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.desugar.records.RecordTestUtils;
import com.android.tools.r8.profile.art.model.ExternalArtProfile;
import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
import com.android.tools.r8.references.ClassReference;
@@ -43,26 +43,12 @@
@RunWith(Parameterized.class)
public class RecordProfileRewritingTest extends TestBase {
- private static final String RECORD_NAME = "SimpleRecord";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
private static final String EXPECTED_RESULT =
StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "true",
- "true",
- "false",
- "false",
- "false",
- "false");
+ "Jane Doe", "42", "true", "true", "true", "false", "false", "false", "false");
- private static final ClassReference MAIN_REFERENCE =
- Reference.classFromTypeName(RecordTestUtils.getMainType(RECORD_NAME));
- private static final ClassReference PERSON_REFERENCE =
- Reference.classFromTypeName(MAIN_REFERENCE.getTypeName() + "$Person");
+ private static final ClassReference MAIN_REFERENCE = Reference.classFromClass(SimpleRecord.class);
+ private static final ClassReference PERSON_REFERENCE = Reference.classFromClass(Person.class);
private static final ClassReference RECORD_REFERENCE =
Reference.classFromTypeName("java.lang.Record");
private static final ClassReference OBJECT_REFERENCE = Reference.classFromClass(Object.class);
@@ -81,7 +67,7 @@
parameters.assumeJvmTestParameters();
assumeTrue(runtimeWithRecordsSupport(parameters.getRuntime()));
testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.run(parameters.getRuntime(), MAIN_REFERENCE.getTypeName())
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -90,7 +76,7 @@
public void testD8() throws Exception {
D8TestCompileResult compileResult =
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.addArtProfileForRewriting(getArtProfile())
.setMinApi(parameters)
.compile();
@@ -114,7 +100,7 @@
assumeTrue(runtimeWithRecordsSupport(parameters.getRuntime()) || parameters.isDexRuntime());
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.addKeepMainRule(MAIN_REFERENCE.getTypeName())
.addKeepRules(
"-neverpropagatevalue class " + PERSON_REFERENCE.getTypeName() + " { <fields>; }")
@@ -122,8 +108,7 @@
.addOptionsModification(InlinerOptions::disableInlining)
.applyIf(
parameters.isCfRuntime(),
- testBuilder ->
- testBuilder.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp)))
+ testBuilder -> testBuilder.addLibraryProvider(JdkClassFileProvider.fromSystemJdk()))
.enableProguardTestOptions()
.noHorizontalClassMergingOfSynthetics()
.setMinApi(parameters)
@@ -218,7 +203,7 @@
: recordTagClassSubject.asTypeSubject(),
personRecordClassSubject.getSuperType());
assertEquals(
- recordDesugaringIsOff ? 6 : (canMergeRecordTag && !partialDesugaring) ? 11 : 10,
+ recordDesugaringIsOff ? 6 : (canMergeRecordTag && !partialDesugaring) ? 9 : 8,
personRecordClassSubject.allMethods().size());
MethodSubject personDefaultInstanceInitializerSubject = personRecordClassSubject.init();
@@ -236,24 +221,10 @@
MethodSubject nameMethodSubject = personRecordClassSubject.uniqueMethodWithOriginalName("name");
assertThat(nameMethodSubject, isPresent());
- MethodSubject nameNestAccessorMethodSubject =
- personRecordClassSubject.uniqueMethodWithOriginalName(
- SyntheticItemsTestUtils.syntheticNestInstanceFieldGetter(
- Reference.field(PERSON_REFERENCE, "name", STRING_REFERENCE))
- .getMethodName());
- assertThat(nameNestAccessorMethodSubject, isAbsentIf(canUseNestBasedAccesses));
-
// Age getters.
MethodSubject ageMethodSubject = personRecordClassSubject.uniqueMethodWithOriginalName("age");
assertThat(ageMethodSubject, isPresent());
- MethodSubject ageNestAccessorMethodSubject =
- personRecordClassSubject.uniqueMethodWithOriginalName(
- SyntheticItemsTestUtils.syntheticNestInstanceFieldGetter(
- Reference.field(PERSON_REFERENCE, "age", Reference.INT))
- .getMethodName());
- assertThat(ageNestAccessorMethodSubject, isAbsentIf(canUseNestBasedAccesses));
-
// boolean equals(Object)
MethodSubject getFieldsAsObjectsMethodSubject =
personRecordClassSubject.uniqueMethodWithOriginalName(GET_FIELDS_AS_OBJECTS_METHOD_NAME);
@@ -272,7 +243,7 @@
// int hashCode()
ClassSubject hashCodeHelperClassSubject =
- inspector.clazz(SyntheticItemsTestUtils.syntheticRecordHelperClass(PERSON_REFERENCE, 1));
+ inspector.clazz(SyntheticItemsTestUtils.syntheticRecordHelperClass(PERSON_REFERENCE, 0));
assertThat(hashCodeHelperClassSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject hashCodeHelperMethodSubject = hashCodeHelperClassSubject.uniqueMethod();
@@ -290,7 +261,7 @@
// String toString()
ClassSubject toStringHelperClassSubject =
- inspector.clazz(SyntheticItemsTestUtils.syntheticRecordHelperClass(PERSON_REFERENCE, 0));
+ inspector.clazz(SyntheticItemsTestUtils.syntheticRecordHelperClass(PERSON_REFERENCE, 1));
assertThat(toStringHelperClassSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject toStringHelperMethodSubject = toStringHelperClassSubject.uniqueMethod();
@@ -317,11 +288,6 @@
hashCodeMethodSubject,
toStringMethodSubject)
.applyIf(
- !canUseNestBasedAccesses,
- i ->
- i.assertContainsMethodRules(
- nameNestAccessorMethodSubject, ageNestAccessorMethodSubject))
- .applyIf(
canMergeRecordTag && !partialDesugaring,
i -> i.assertContainsMethodRule(personDefaultInstanceInitializerSubject))
.applyIf(
@@ -340,4 +306,32 @@
toStringHelperMethodSubject))
.assertContainsNoOtherRules();
}
+
+ record Person(String name, int age) {}
+
+ public class SimpleRecord {
+
+ public static void main(String[] args) {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.name());
+ System.out.println(janeDoe.age());
+
+ // Test equals with self.
+ System.out.println(janeDoe.equals(janeDoe));
+
+ // Test equals with structurally equals Person.
+ Person otherJaneDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.equals(otherJaneDoe));
+ System.out.println(otherJaneDoe.equals(janeDoe));
+
+ // Test equals with not-structually equals Person.
+ Person johnDoe = new Person("John Doe", 42);
+ System.out.println(janeDoe.equals(johnDoe));
+ System.out.println(johnDoe.equals(janeDoe));
+
+ // Test equals with Object and null.
+ System.out.println(janeDoe.equals(new Object()));
+ System.out.println(janeDoe.equals(null));
+ }
+ }
}
diff --git a/src/test/examplesJava17/records/RecordReflection.java b/src/test/examplesJava17/records/RecordReflection.java
deleted file mode 100644
index 1b94a12..0000000
--- a/src/test/examplesJava17/records/RecordReflection.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2020, 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 records;
-
-import java.util.Arrays;
-
-public class RecordReflection {
-
- record Empty(){}
-
- record Person(String name, int age) {}
-
- record PersonGeneric <S extends CharSequence>(S name, int age) {}
-
- public static void main(String[] args) {
- System.out.println(Empty.class.isRecord());
- System.out.println(Arrays.toString(Empty.class.getRecordComponents()));
- System.out.println(Person.class.isRecord());
- System.out.println(Arrays.toString(Person.class.getRecordComponents()));
- System.out.println(PersonGeneric.class.isRecord());
- System.out.println(Arrays.toString(PersonGeneric.class.getRecordComponents()));
- System.out.println(Arrays.toString(PersonGeneric.class.getTypeParameters()));
- System.out.println(Object.class.isRecord());
- System.out.println(Arrays.toString(Object.class.getRecordComponents()));
- }
-
-}
diff --git a/src/test/examplesJava17/records/RecordReflectionTest.java b/src/test/examplesJava17/records/RecordReflectionTest.java
new file mode 100644
index 0000000..bab9fb7
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordReflectionTest.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2021, 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 records;
+
+import com.android.tools.r8.JdkClassFileProvider;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RecordReflectionTest extends TestBase {
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "true",
+ "[]",
+ "true",
+ "[java.lang.String name, int age]",
+ "true",
+ "[java.lang.CharSequence name, int age]",
+ "[S]",
+ "false",
+ "null");
+
+ private final TestParameters parameters;
+
+ public RecordReflectionTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK17).build();
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeJvmTestParameters();
+ testForJvm(parameters)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordReflection.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testR8Cf() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClassesAndStrippedOuter(getClass())
+ .setMinApi(parameters)
+ .addKeepMainRule(RecordReflection.class)
+ .addKeepAllAttributes()
+ .addKeepRules("-keep class * extends java.lang.Record { private final <fields>; }")
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
+ .compile()
+ .inspect(RecordTestUtils::assertRecordsAreRecords)
+ .enableJVMPreview()
+ .run(parameters.getRuntime(), RecordReflection.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ record Empty() {}
+
+ record Person(String name, int age) {}
+
+ record PersonGeneric<S extends CharSequence>(S name, int age) {}
+
+ public class RecordReflection {
+
+ public static void main(String[] args) {
+ System.out.println(Empty.class.isRecord());
+ System.out.println(Arrays.toString(Empty.class.getRecordComponents()));
+ System.out.println(Person.class.isRecord());
+ System.out.println(Arrays.toString(Person.class.getRecordComponents()));
+ System.out.println(PersonGeneric.class.isRecord());
+ System.out.println(Arrays.toString(PersonGeneric.class.getRecordComponents()));
+ System.out.println(Arrays.toString(PersonGeneric.class.getTypeParameters()));
+ System.out.println(Object.class.isRecord());
+ System.out.println(Arrays.toString(Object.class.getRecordComponents()));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java b/src/test/examplesJava17/records/RecordShrinkFieldTest.java
similarity index 72%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
rename to src/test/examplesJava17/records/RecordShrinkFieldTest.java
index e8587ca..232f02f 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
+++ b/src/test/examplesJava17/records/RecordShrinkFieldTest.java
@@ -2,10 +2,11 @@
// 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.records;
+package records;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -22,17 +23,13 @@
@RunWith(Parameterized.class)
public class RecordShrinkFieldTest extends TestBase {
- private static final String RECORD_NAME = "RecordShrinkField";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
-
private static final String EXPECTED_RESULT_D8 =
StringUtils.lines(
"Person[unused=-1, name=Jane Doe, age=42]", "Person[unused=-1, name=Bob, age=42]");
private static final String EXPECTED_RESULT_R8 = StringUtils.lines("a[a=Jane Doe]", "a[a=Bob]");
private static final String EXPECTED_RESULT_R8_NO_MINIFICATION =
StringUtils.lines(
- "RecordShrinkField$Person[name=Jane Doe]", "RecordShrinkField$Person[name=Bob]");
+ "RecordShrinkFieldTest$Person[name=Jane Doe]", "RecordShrinkFieldTest$Person[name=Bob]");
private final TestParameters parameters;
private final boolean minifying;
@@ -53,10 +50,10 @@
public void testD8() throws Exception {
Assume.assumeTrue("Only valid in R8", minifying);
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordShrinkField.class)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
}
@@ -64,13 +61,13 @@
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE)
+ .addKeepMainRule(RecordShrinkField.class)
.addDontObfuscateUnless(minifying)
.compile()
.inspect(inspector -> inspect(inspector, false))
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordShrinkField.class)
.assertSuccessWithOutput(
minifying ? EXPECTED_RESULT_R8 : EXPECTED_RESULT_R8_NO_MINIFICATION);
}
@@ -80,28 +77,27 @@
parameters.assumeR8TestParameters();
Path desugared =
testForR8(Backend.CF)
- .addProgramClassFileData(PROGRAM_DATA)
- .addKeepMainRule(MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addKeepMainRule(RecordShrinkField.class)
.addDontObfuscateUnless(minifying)
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.writeToZip();
testForR8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE)
+ .addKeepMainRule(RecordShrinkField.class)
.addDontObfuscateUnless(minifying)
.compile()
.inspect(inspector -> inspect(inspector, true))
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordShrinkField.class)
.assertSuccessWithOutput(
minifying ? EXPECTED_RESULT_R8 : EXPECTED_RESULT_R8_NO_MINIFICATION);
}
private void inspect(CodeInspector inspector, boolean isCfThenDex) {
- ClassSubject recordClass =
- inspector.clazz(minifying ? "records.a" : "records.RecordShrinkField$Person");
- if (isCfThenDex || !minifying) {
+ ClassSubject recordClass = inspector.clazz(Person.class);
+ if (!isCfThenDex || !minifying) {
assertEquals(1, recordClass.allInstanceFields().size());
assertEquals(
"java.lang.String", recordClass.allInstanceFields().get(0).getField().type().toString());
@@ -109,4 +105,20 @@
assertEquals(0, recordClass.allInstanceFields().size());
}
}
+
+ record Person(int unused, String name, int age) {
+ Person(String name, int age) {
+ this(-1, name, age);
+ }
+ }
+
+ public class RecordShrinkField {
+
+ public static void main(String[] args) {
+ Person jane = new Person("Jane Doe", 42);
+ Person bob = new Person("Bob", 42);
+ System.out.println(jane);
+ System.out.println(bob);
+ }
+ }
}
diff --git a/src/test/examplesJava17/records/RecordWithAnnotations.java b/src/test/examplesJava17/records/RecordWithAnnotations.java
deleted file mode 100644
index fe9fd95..0000000
--- a/src/test/examplesJava17/records/RecordWithAnnotations.java
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2023, 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 records;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Field;
-import java.lang.reflect.RecordComponent;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-
-public class RecordWithAnnotations {
-
- @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
- @Retention(RetentionPolicy.RUNTIME)
- @interface Annotation {
- String value();
- }
-
- @Target(ElementType.FIELD)
- @Retention(RetentionPolicy.RUNTIME)
- @interface AnnotationFieldOnly {
- String value();
- }
-
- @Target(ElementType.RECORD_COMPONENT)
- @Retention(RetentionPolicy.RUNTIME)
- @interface AnnotationRecordComponentOnly {
- String value();
- }
-
- record Person(
- @Annotation("a") @AnnotationFieldOnly("b") @AnnotationRecordComponentOnly("c") String name,
- @Annotation("x") @AnnotationFieldOnly("y") @AnnotationRecordComponentOnly("z") int age) {}
-
- public static void main(String[] args) {
- Person janeDoe = new Person("Jane Doe", 42);
- System.out.println(janeDoe.name);
- System.out.println(janeDoe.age);
- System.out.println(janeDoe.name());
- System.out.println(janeDoe.age());
- try {
- Class.class.getDeclaredMethod("isRecord");
- } catch (NoSuchMethodException e) {
- System.out.println("Class.isRecord not present");
- return;
- }
- System.out.println(Person.class.isRecord());
- if (Person.class.isRecord()) {
- System.out.println(Person.class.getRecordComponents().length);
- for (int i = 0; i < Person.class.getRecordComponents().length; i++) {
- RecordComponent c = Person.class.getRecordComponents()[i];
- System.out.println(c.getName());
- System.out.println(c.getType().getName());
- System.out.println(c.getGenericSignature() == null);
- System.out.println(c.getAnnotations().length);
- // Collect and sort the annotations, as the order is not deterministic on Art (tested
- // on Art 14 Beta 3).
- List<String> annotations = new ArrayList<>();
- for (int j = 0; j < c.getAnnotations().length; j++) {
- annotations.add(c.getAnnotations()[j].toString());
- }
- annotations.sort(Comparator.naturalOrder());
- for (int j = 0; j < annotations.size(); j++) {
- System.out.println(annotations.get(j));
- }
- }
- System.out.println(Person.class.getDeclaredFields().length);
- List<Field> fields = new ArrayList<>();
- for (int i = 0; i < Person.class.getDeclaredFields().length; i++) {
- fields.add(Person.class.getDeclaredFields()[i]);
- }
- fields.sort(
- new Comparator<Field>() {
- @Override
- public int compare(Field o1, Field o2) {
- return o1.getName().compareTo(o2.getName());
- }
- });
- for (int i = 0; i < fields.size(); i++) {
- Field f = fields.get(i);
- System.out.println(f.getDeclaredAnnotations().length);
- List<String> annotations = new ArrayList<>();
- for (int j = 0; j < f.getDeclaredAnnotations().length; j++) {
- annotations.add(f.getAnnotations()[j].toString());
- }
- annotations.sort(Comparator.naturalOrder());
- for (int j = 0; j < annotations.size(); j++) {
- System.out.println(annotations.get(j));
- }
- }
- }
- }
-}
diff --git a/src/test/examplesJava17/records/RecordWithConstClass.java b/src/test/examplesJava17/records/RecordWithConstClass.java
deleted file mode 100644
index db06f51..0000000
--- a/src/test/examplesJava17/records/RecordWithConstClass.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2021, 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 records;
-
-import records.differentpackage.PrivateConstClass;
-
-public class RecordWithConstClass {
-
- record MyRecordWithConstClass(Class<?> theClass) { }
-
- public static void main(String[] args) {
- MyRecordWithConstClass inst =
- new MyRecordWithConstClass(PrivateConstClass.getPrivateConstClass());
- System.out.println(inst);
- }
-}
diff --git a/src/test/examplesJava17/records/RecordWithMembers.java b/src/test/examplesJava17/records/RecordWithMembers.java
deleted file mode 100644
index 6de2b99..0000000
--- a/src/test/examplesJava17/records/RecordWithMembers.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2020, 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 records;
-
-public class RecordWithMembers {
-
-
- record PersonWithConstructors(String name, int age) {
-
- public PersonWithConstructors(String name, int age) {
- this.name = name + "X";
- this.age = age;
- }
-
- public PersonWithConstructors(String name) {
- this(name, -1);
- }
- }
-
- record PersonWithMethods(String name, int age) {
- public static void staticPrint() {
- System.out.println("print");
- }
-
- @Override
- public String toString() {
- return name + age;
- }
- }
-
- record PersonWithFields(String name, int age) {
-
- // Extra instance fields are not allowed on records.
- public static String globalName;
-
- }
-
- public static void main(String[] args) {
- personWithConstructorTest();
- personWithMethodsTest();
- personWithFieldsTest();
- }
-
- private static void personWithConstructorTest() {
- PersonWithConstructors bob = new PersonWithConstructors("Bob", 43);
- System.out.println(bob.name);
- System.out.println(bob.age);
- System.out.println(bob.name());
- System.out.println(bob.age());
- PersonWithConstructors felix = new PersonWithConstructors("Felix");
- System.out.println(felix.name);
- System.out.println(felix.age);
- System.out.println(felix.name());
- System.out.println(felix.age());
- }
-
- private static void personWithMethodsTest() {
- PersonWithMethods.staticPrint();
- PersonWithMethods bob = new PersonWithMethods("Bob", 43);
- System.out.println(bob.toString());
- }
-
- private static void personWithFieldsTest() {
- PersonWithFields.globalName = "extra";
- System.out.println(PersonWithFields.globalName);
- }
-}
diff --git a/src/test/examplesJava17/records/RecordWithMembersTest.java b/src/test/examplesJava17/records/RecordWithMembersTest.java
new file mode 100644
index 0000000..41d36ea
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordWithMembersTest.java
@@ -0,0 +1,137 @@
+// Copyright (c) 2021, 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 records;
+
+import com.android.tools.r8.JdkClassFileProvider;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RecordWithMembersTest extends TestBase {
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines("BobX", "43", "FelixX", "-1", "print", "Bob43", "extra");
+
+ private final TestParameters parameters;
+
+ public RecordWithMembersTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+ .withDexRuntimes()
+ .withAllApiLevelsAlsoForCf()
+ .build();
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeJvmTestParameters();
+ testForJvm(parameters)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), RecordWithMembers.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addInnerClassesAndStrippedOuter(getClass())
+ .setMinApi(parameters)
+ .compile()
+ .run(parameters.getRuntime(), RecordWithMembers.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ parameters.assumeR8TestParameters();
+ R8FullTestBuilder builder =
+ testForR8(parameters.getBackend())
+ .addInnerClassesAndStrippedOuter(getClass())
+ .setMinApi(parameters)
+ .addKeepMainRule(RecordWithMembers.class);
+ if (parameters.isCfRuntime()) {
+ builder
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
+ .compile()
+ .inspect(RecordTestUtils::assertRecordsAreRecords)
+ .run(parameters.getRuntime(), RecordWithMembers.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ return;
+ }
+ builder
+ .run(parameters.getRuntime(), RecordWithMembers.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ record PersonWithConstructors(String name, int age) {
+
+ public PersonWithConstructors(String name, int age) {
+ this.name = name + "X";
+ this.age = age;
+ }
+
+ public PersonWithConstructors(String name) {
+ this(name, -1);
+ }
+ }
+
+ record PersonWithMethods(String name, int age) {
+ public static void staticPrint() {
+ System.out.println("print");
+ }
+
+ @Override
+ public String toString() {
+ return name + age;
+ }
+ }
+
+ record PersonWithFields(String name, int age) {
+
+ // Extra instance fields are not allowed on records.
+ public static String globalName;
+ }
+
+ public class RecordWithMembers {
+
+ public static void main(String[] args) {
+ personWithConstructorTest();
+ personWithMethodsTest();
+ personWithFieldsTest();
+ }
+
+ private static void personWithConstructorTest() {
+ PersonWithConstructors bob = new PersonWithConstructors("Bob", 43);
+ System.out.println(bob.name());
+ System.out.println(bob.age());
+ PersonWithConstructors felix = new PersonWithConstructors("Felix");
+ System.out.println(felix.name());
+ System.out.println(felix.age());
+ }
+
+ private static void personWithMethodsTest() {
+ PersonWithMethods.staticPrint();
+ PersonWithMethods bob = new PersonWithMethods("Bob", 43);
+ System.out.println(bob.toString());
+ }
+
+ private static void personWithFieldsTest() {
+ PersonWithFields.globalName = "extra";
+ System.out.println(PersonWithFields.globalName);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java b/src/test/examplesJava17/records/RecordWithNonMaterializableConstClassTest.java
similarity index 67%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
rename to src/test/examplesJava17/records/RecordWithNonMaterializableConstClassTest.java
index bcf4294..4cda982 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
+++ b/src/test/examplesJava17/records/RecordWithNonMaterializableConstClassTest.java
@@ -2,9 +2,9 @@
// 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.records;
+package records;
-
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -17,24 +17,19 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+import records.differentpackage.PrivateConstClass;
@RunWith(Parameterized.class)
public class RecordWithNonMaterializableConstClassTest extends TestBase {
- private static final String RECORD_NAME = "RecordWithConstClass";
private static final String PRIVATE_CLASS_NAME =
"records.differentpackage.PrivateConstClass$PrivateClass";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final byte[][] EXTRA_DATA =
- RecordTestUtils.getProgramData("differentpackage/PrivateConstClass");
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
+ private static final Class<?> EXTRA_DATA = PrivateConstClass.class;
private static final String EXPECTED_RESULT_FORMAT =
StringUtils.lines("%s[%s=class " + PRIVATE_CLASS_NAME + "]");
private static final String EXPECTED_RESULT_D8 =
String.format(EXPECTED_RESULT_FORMAT, "MyRecordWithConstClass", "theClass");
private static final String EXPECTED_RESULT_R8 = String.format(EXPECTED_RESULT_FORMAT, "a", "a");
- private static final String EXPECTED_RESULT_R8_ART14 =
- String.format(EXPECTED_RESULT_FORMAT, "a", "theClass");
@Parameter(0)
public TestParameters parameters;
@@ -52,20 +47,22 @@
public void testJvm() throws Exception {
parameters.assumeJvmTestParameters();
testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .addProgramClassFileData(EXTRA_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addProgramClasses(EXTRA_DATA)
+ .addInnerClasses(EXTRA_DATA)
+ .run(parameters.getRuntime(), RecordWithConstClass.class)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
}
@Test
public void testD8() throws Exception {
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .addProgramClassFileData(EXTRA_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addProgramClasses(EXTRA_DATA)
+ .addInnerClasses(EXTRA_DATA)
.setMinApi(parameters)
.compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordWithConstClass.class)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
}
@@ -73,12 +70,13 @@
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .addProgramClassFileData(EXTRA_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addProgramClasses(EXTRA_DATA)
+ .addInnerClasses(EXTRA_DATA)
.apply(this::configureR8)
.setMinApi(parameters)
.compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordWithConstClass.class)
.assertSuccessWithOutput(EXPECTED_RESULT_R8);
}
@@ -87,9 +85,10 @@
parameters.assumeR8TestParameters();
Path desugared =
testForR8(Backend.CF)
- .addProgramClassFileData(PROGRAM_DATA)
- .addProgramClassFileData(EXTRA_DATA)
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addInnerClassesAndStrippedOuter(getClass())
+ .addProgramClasses(EXTRA_DATA)
+ .addInnerClasses(EXTRA_DATA)
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.apply(this::configureR8)
.compile()
.writeToZip();
@@ -100,16 +99,27 @@
.apply(this::configureR8)
.setMinApi(parameters)
.compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), RecordWithConstClass.class)
.assertSuccessWithOutput(EXPECTED_RESULT_R8);
}
private void configureR8(R8FullTestBuilder testBuilder) {
testBuilder
- .addKeepMainRule(MAIN_TYPE)
+ .addKeepMainRule(RecordWithConstClass.class)
.addKeepRules("-keep class " + PRIVATE_CLASS_NAME)
.applyIf(
parameters.isCfRuntime(),
- b -> b.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp)));
+ b -> b.addLibraryProvider(JdkClassFileProvider.fromSystemJdk()));
+ }
+
+ record MyRecordWithConstClass(Class<?> theClass) {}
+
+ public static class RecordWithConstClass {
+
+ public static void main(String[] args) {
+ MyRecordWithConstClass inst =
+ new MyRecordWithConstClass(PrivateConstClass.getPrivateConstClass());
+ System.out.println(inst);
+ }
}
}
diff --git a/src/test/examplesJava17/records/RecordWithSignature.java b/src/test/examplesJava17/records/RecordWithSignature.java
deleted file mode 100644
index be31024..0000000
--- a/src/test/examplesJava17/records/RecordWithSignature.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2023, 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 records;
-
-import java.lang.reflect.RecordComponent;
-
-public class RecordWithSignature {
-
- record Person<N extends CharSequence, A>(N name, A age) {}
-
- public static void main(String[] args) {
- Person<String, Integer> janeDoe = new Person<>("Jane Doe", 42);
- System.out.println(janeDoe.name);
- System.out.println(janeDoe.age);
- System.out.println(janeDoe.name());
- System.out.println(janeDoe.age());
- try {
- Class.class.getDeclaredMethod("isRecord");
- } catch (NoSuchMethodException e) {
- System.out.println("Class.isRecord not present");
- return;
- }
- System.out.println(Person.class.isRecord());
- if (Person.class.isRecord()) {
- System.out.println(Person.class.getRecordComponents().length);
- for (int i = 0; i < Person.class.getRecordComponents().length; i++) {
- RecordComponent c = Person.class.getRecordComponents()[i];
- System.out.println(c.getName());
- System.out.println(c.getType().getName());
- System.out.println(c.getGenericSignature());
- System.out.println(c.getAnnotations().length);
- }
- }
- }
-}
diff --git a/src/test/examplesJava17/records/SimpleRecord.java b/src/test/examplesJava17/records/SimpleRecord.java
deleted file mode 100644
index 3f908dc..0000000
--- a/src/test/examplesJava17/records/SimpleRecord.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2020, 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 records;
-
-public class SimpleRecord {
-
- record Person(String name, int age) {}
-
- public static void main(String[] args) {
- Person janeDoe = new Person("Jane Doe", 42);
- System.out.println(janeDoe.name);
- System.out.println(janeDoe.age);
- System.out.println(janeDoe.name());
- System.out.println(janeDoe.age());
-
- // Test equals with self.
- System.out.println(janeDoe.equals(janeDoe));
-
- // Test equals with structurally equals Person.
- Person otherJaneDoe = new Person("Jane Doe", 42);
- System.out.println(janeDoe.equals(otherJaneDoe));
- System.out.println(otherJaneDoe.equals(janeDoe));
-
- // Test equals with not-structually equals Person.
- Person johnDoe = new Person("John Doe", 42);
- System.out.println(janeDoe.equals(johnDoe));
- System.out.println(johnDoe.equals(janeDoe));
-
- // Test equals with Object and null.
- System.out.println(janeDoe.equals(new Object()));
- System.out.println(janeDoe.equals(null));
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/examplesJava17/records/SimpleRecordTest.java
similarity index 71%
rename from src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
rename to src/test/examplesJava17/records/SimpleRecordTest.java
index 9dbd8d2..d7c8131 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/examplesJava17/records/SimpleRecordTest.java
@@ -2,18 +2,18 @@
// 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.records;
+package records;
-import static com.android.tools.r8.desugar.records.RecordTestUtils.assertNoJavaLangRecord;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.GlobalSyntheticsConsumer;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -28,22 +28,9 @@
@RunWith(Parameterized.class)
public class SimpleRecordTest extends TestBase {
- private static final String RECORD_NAME = "SimpleRecord";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
private static final String EXPECTED_RESULT =
StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "true",
- "true",
- "false",
- "false",
- "false",
- "false");
+ "Jane Doe", "42", "true", "true", "true", "false", "false", "false", "false");
@Parameter(0)
public TestParameters parameters;
@@ -69,8 +56,8 @@
assumeTrue(isCfRuntimeWithNativeRecordSupport());
assumeFalse(forceInvokeRangeForInvokeCustom);
testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .addInnerClassesAndStrippedOuter(getClass())
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -78,13 +65,13 @@
public void testD8() throws Exception {
assumeFalse(forceInvokeRangeForInvokeCustom);
testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.compile()
.inspectWithOptions(
- i -> assertNoJavaLangRecord(i, parameters),
+ i -> RecordTestUtils.assertNoJavaLangRecord(i, parameters),
options -> options.testing.disableRecordApplicationReaderMap = true)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.applyIf(
isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -108,7 +95,7 @@
.addGlobalSyntheticsResourceProviders(globals.getIndexedModeProvider()))
.setMinApi(parameters)
.setIncludeClassesChecksum(true)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -129,14 +116,14 @@
.setMinApi(parameters)
.setIncludeClassesChecksum(true)
.disableDesugaring()
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
private Path compileIntermediate(GlobalSyntheticsConsumer globalSyntheticsConsumer)
throws Exception {
return testForD8(Backend.DEX)
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
.setIntermediate(true)
.setIncludeClassesChecksum(true)
@@ -156,25 +143,25 @@
opptions ->
opptions.testing.forceInvokeRangeForInvokeCustom =
forceInvokeRangeForInvokeCustom)
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE);
+ .addKeepMainRule(SimpleRecord.class);
if (parameters.isCfRuntime()) {
builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.inspect(RecordTestUtils::assertRecordsAreRecords)
- .inspect(inspector -> inspector.clazz("records.SimpleRecord$Person").isRenamed())
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .inspect(inspector -> inspector.clazz(Person.class).isRenamed())
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
return;
}
builder
.compile()
.inspectWithOptions(
- i -> assertNoJavaLangRecord(i, parameters),
+ i -> RecordTestUtils.assertNoJavaLangRecord(i, parameters),
options -> options.testing.disableRecordApplicationReaderMap = true)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -185,25 +172,53 @@
assumeTrue(forceInvokeRangeForInvokeCustom || !parameters.isDexRuntime());
R8FullTestBuilder builder =
testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
+ .addInnerClassesAndStrippedOuter(getClass())
.addDontObfuscate()
.setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE);
+ .addKeepMainRule(SimpleRecord.class);
if (parameters.isCfRuntime()) {
builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+ .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
.compile()
.inspect(RecordTestUtils::assertRecordsAreRecords)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
return;
}
builder
.compile()
.inspectWithOptions(
- i -> assertNoJavaLangRecord(i, parameters),
+ i -> RecordTestUtils.assertNoJavaLangRecord(i, parameters),
options -> options.testing.disableRecordApplicationReaderMap = true)
- .run(parameters.getRuntime(), MAIN_TYPE)
+ .run(parameters.getRuntime(), SimpleRecord.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
+
+ record Person(String name, int age) {}
+
+ public class SimpleRecord {
+
+ public static void main(String[] args) {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.name());
+ System.out.println(janeDoe.age());
+
+ // Test equals with self.
+ System.out.println(janeDoe.equals(janeDoe));
+
+ // Test equals with structurally equals Person.
+ Person otherJaneDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.equals(otherJaneDoe));
+ System.out.println(otherJaneDoe.equals(janeDoe));
+
+ // Test equals with not-structually equals Person.
+ Person johnDoe = new Person("John Doe", 42);
+ System.out.println(janeDoe.equals(johnDoe));
+ System.out.println(johnDoe.equals(janeDoe));
+
+ // Test equals with Object and null.
+ System.out.println(janeDoe.equals(new Object()));
+ System.out.println(janeDoe.equals(null));
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
index d3514ae..3ead5bf 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
@@ -16,13 +16,13 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java
index 4c99837..af120aa 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -19,7 +20,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index a4aa543..e321b56 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -11,6 +11,7 @@
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
@@ -18,7 +19,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionAndroidApiTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionAndroidApiTest.java
index 2a7ebee..288a050 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionAndroidApiTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionAndroidApiTest.java
@@ -9,6 +9,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8TestCompileResult;
@@ -19,7 +20,6 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionInstantiateAndCatchTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionInstantiateAndCatchTest.java
index e212a7a..e7508c5 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionInstantiateAndCatchTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionInstantiateAndCatchTest.java
@@ -11,6 +11,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -18,7 +19,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionTest.java
index 7b98e5c..898bd3e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockExceptionTest.java
@@ -11,6 +11,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -18,7 +19,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
index bb28672..eaa397f 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
@@ -12,13 +12,13 @@
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
index 15ffd25..a67674e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
@@ -12,13 +12,13 @@
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java
index 880360d..a02fe01 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java
@@ -12,13 +12,13 @@
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
index 258805a..c890f40 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
index 6c11011..bfd0048 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
@@ -8,6 +8,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
index aab7123..42f49fb 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
index cdb01f6..37674a7 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
index df53dc1..4f97f34 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java b/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
index 650338c..629de48 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
@@ -5,6 +5,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.DesugarGraphTestConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
deleted file mode 100644
index 41f97f8..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright (c) 2023, 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.records;
-
-import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasAnnotationTypes;
-import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasElements;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.TestShrinkerBuilder;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.FieldSubject;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class RecordComponentAnnotationsTest extends TestBase {
-
- private static final String RECORD_NAME = "RecordWithAnnotations";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
- private static final String JVM_UNTIL_20_EXPECTED_RESULT =
- StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "2",
- "name",
- "java.lang.String",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"a\")",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"c\")",
- "age",
- "int",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"x\")",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"z\")",
- "2",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"x\")",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(\"y\")",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"a\")",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(\"b\")");
- private static final String JVM_FROM_21_EXPECTED_RESULT =
- JVM_UNTIL_20_EXPECTED_RESULT.replaceAll(
- "RecordWithAnnotations\\$Annotation", "RecordWithAnnotations.Annotation");
- private static final String ART_EXPECTED_RESULT =
- StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "2",
- "name",
- "java.lang.String",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=a)",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(value=c)",
- "age",
- "int",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=x)",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(value=z)",
- "2",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=x)",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(value=y)",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=a)",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(value=b)");
- private static final String JVM_EXPECTED_RESULT_R8 =
- StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "2",
- "a",
- "java.lang.String",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"a\")",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"c\")",
- "b",
- "int",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"x\")",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"z\")",
- "2",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"a\")",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(\"b\")",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"x\")",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(\"y\")");
- private static final String ART_EXPECTED_RESULT_R8 =
- StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "2",
- "a",
- "java.lang.String",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=a)",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(value=c)",
- "b",
- "int",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=x)",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(value=z)",
- "2",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=a)",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(value=b)",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=x)",
- "@records.RecordWithAnnotations$AnnotationFieldOnly(value=y)");
- private static final String JVM_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS =
- StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "2",
- "a",
- "java.lang.String",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"a\")",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"c\")",
- "b",
- "int",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(\"x\")",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(\"z\")",
- "2",
- "0",
- "0");
- private static final String ART_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS =
- StringUtils.lines(
- "Jane Doe",
- "42",
- "Jane Doe",
- "42",
- "true",
- "2",
- "a",
- "java.lang.String",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=a)",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(value=c)",
- "b",
- "int",
- "true",
- "2",
- "@records.RecordWithAnnotations$Annotation(value=x)",
- "@records.RecordWithAnnotations$AnnotationRecordComponentOnly(value=z)",
- "2",
- "0",
- "0");
- private static final String EXPECTED_RESULT_DESUGARED_RECORD_SUPPORT =
- StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "false");
- private static final String EXPECTED_RESULT_DESUGARED_NO_RECORD_SUPPORT =
- StringUtils.lines("Jane Doe", "42", "Jane Doe", "42", "Class.isRecord not present");
-
- @Parameter(0)
- public TestParameters parameters;
-
- @Parameter(1)
- public Boolean keepAnnotations;
-
- // Enable once records are no longer partially desugared on platform.
- public boolean recordDesugaringIsOffOnDex = false;
-
- @Parameters(name = "{0}, keepAnnotations: {1}")
- public static List<Object[]> data() {
- return buildParameters(
- getTestParameters()
- .withDexRuntimesAndAllApiLevels()
- .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
- .withAllApiLevelsAlsoForCf()
- .build(),
- BooleanUtils.values());
- }
-
- @Test
- public void testJvm() throws Exception {
- parameters.assumeJvmTestParameters();
- assumeTrue(keepAnnotations);
- testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(
- parameters.getRuntime().asCf().getVm().isLessThanOrEqualTo(CfVm.JDK20)
- ? JVM_UNTIL_20_EXPECTED_RESULT
- : JVM_FROM_21_EXPECTED_RESULT);
- }
-
- @Test
- public void testDesugaring() throws Exception {
- parameters.assumeDexRuntime();
- assumeTrue(keepAnnotations);
- testForDesugaring(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .applyIf(
- parameters.isDexRuntime(),
- r ->
- r.assertSuccessWithOutput(
- runtimeWithRecordsSupport(parameters.getRuntime())
- ? EXPECTED_RESULT_DESUGARED_RECORD_SUPPORT
- : EXPECTED_RESULT_DESUGARED_NO_RECORD_SUPPORT),
- r ->
- r.assertSuccessWithOutput(ART_EXPECTED_RESULT)
- .inspect(
- inspector -> {
- ClassSubject person =
- inspector.clazz("records.RecordWithAnnotations$Person");
- FieldSubject name = person.uniqueFieldWithOriginalName("name");
- assertThat(name, isPresentAndNotRenamed());
- FieldSubject age = person.uniqueFieldWithOriginalName("age");
- assertThat(age, isPresentAndNotRenamed());
- assertEquals(2, person.getFinalRecordComponents().size());
-
- assertEquals(
- name.getFinalName(),
- person.getFinalRecordComponents().get(0).getName());
- assertTrue(
- person
- .getFinalRecordComponents()
- .get(0)
- .getType()
- .is("java.lang.String"));
- assertNull(person.getFinalRecordComponents().get(0).getSignature());
- assertEquals(
- 2, person.getFinalRecordComponents().get(0).getAnnotations().size());
- assertThat(
- person.getFinalRecordComponents().get(0).getAnnotations(),
- hasAnnotationTypes(
- inspector.getTypeSubject(
- "records.RecordWithAnnotations$Annotation"),
- inspector.getTypeSubject(
- "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
- assertThat(
- person.getFinalRecordComponents().get(0).getAnnotations().get(0),
- hasElements(new Pair<>("value", "a")));
- assertThat(
- person.getFinalRecordComponents().get(0).getAnnotations().get(1),
- hasElements(new Pair<>("value", "c")));
-
- assertEquals(
- age.getFinalName(),
- person.getFinalRecordComponents().get(1).getName());
- assertTrue(person.getFinalRecordComponents().get(1).getType().is("int"));
- assertNull(person.getFinalRecordComponents().get(1).getSignature());
- assertEquals(
- 2, person.getFinalRecordComponents().get(1).getAnnotations().size());
- assertThat(
- person.getFinalRecordComponents().get(1).getAnnotations(),
- hasAnnotationTypes(
- inspector.getTypeSubject(
- "records.RecordWithAnnotations$Annotation"),
- inspector.getTypeSubject(
- "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
- assertThat(
- person.getFinalRecordComponents().get(1).getAnnotations().get(0),
- hasElements(new Pair<>("value", "x")));
- assertThat(
- person.getFinalRecordComponents().get(1).getAnnotations().get(1),
- hasElements(new Pair<>("value", "z")));
- }));
- }
-
- @Test
- public void testR8() throws Exception {
- parameters.assumeR8TestParameters();
- testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- // TODO(b/231930852): Change to android.jar for Android U when that contains
- // java.lang.Record.
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addKeepMainRule(MAIN_TYPE)
- .addKeepClassAndMembersRulesWithAllowObfuscation("records.RecordWithAnnotations$Person")
- .addKeepClassAndMembersRules(
- "records.RecordWithAnnotations$Annotation",
- "records.RecordWithAnnotations$AnnotationFieldOnly",
- "records.RecordWithAnnotations$AnnotationRecordComponentOnly")
- .applyIf(keepAnnotations, TestShrinkerBuilder::addKeepRuntimeVisibleAnnotations)
- .setMinApi(parameters)
- .compile()
- .inspect(
- inspector -> {
- ClassSubject person = inspector.clazz("records.RecordWithAnnotations$Person");
- FieldSubject name = person.uniqueFieldWithOriginalName("name");
- FieldSubject age = person.uniqueFieldWithOriginalName("age");
- if (parameters.isCfRuntime()) {
- assertEquals(2, person.getFinalRecordComponents().size());
-
- assertEquals(
- name.getFinalName(), person.getFinalRecordComponents().get(0).getName());
- assertTrue(
- person.getFinalRecordComponents().get(0).getType().is("java.lang.String"));
- assertNull(person.getFinalRecordComponents().get(0).getSignature());
- assertEquals(2, person.getFinalRecordComponents().get(0).getAnnotations().size());
- assertThat(
- person.getFinalRecordComponents().get(0).getAnnotations(),
- hasAnnotationTypes(
- inspector.getTypeSubject("records.RecordWithAnnotations$Annotation"),
- inspector.getTypeSubject(
- "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
- assertThat(
- person.getFinalRecordComponents().get(0).getAnnotations().get(0),
- hasElements(new Pair<>("value", "a")));
- assertThat(
- person.getFinalRecordComponents().get(0).getAnnotations().get(1),
- hasElements(new Pair<>("value", "c")));
-
- assertEquals(
- age.getFinalName(), person.getFinalRecordComponents().get(1).getName());
- assertTrue(person.getFinalRecordComponents().get(1).getType().is("int"));
- assertNull(person.getFinalRecordComponents().get(1).getSignature());
- assertEquals(2, person.getFinalRecordComponents().get(1).getAnnotations().size());
- assertThat(
- person.getFinalRecordComponents().get(1).getAnnotations(),
- hasAnnotationTypes(
- inspector.getTypeSubject("records.RecordWithAnnotations$Annotation"),
- inspector.getTypeSubject(
- "records.RecordWithAnnotations$AnnotationRecordComponentOnly")));
- assertThat(
- person.getFinalRecordComponents().get(1).getAnnotations().get(0),
- hasElements(new Pair<>("value", "x")));
- assertThat(
- person.getFinalRecordComponents().get(1).getAnnotations().get(1),
- hasElements(new Pair<>("value", "z")));
- } else {
- assertEquals(0, person.getFinalRecordComponents().size());
- }
- })
- .run(parameters.getRuntime(), MAIN_TYPE)
- .applyIf(
- // TODO(b/274888318): EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS still has component
- // annotations.
- parameters.isCfRuntime(),
- r ->
- r.assertSuccessWithOutput(
- keepAnnotations
- ? JVM_EXPECTED_RESULT_R8
- : JVM_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS),
- recordDesugaringIsOffOnDex,
- r ->
- r.assertSuccessWithOutput(
- keepAnnotations
- ? ART_EXPECTED_RESULT_R8
- : ART_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS),
- r ->
- r.assertSuccessWithOutput(
- runtimeWithRecordsSupport(parameters.getRuntime())
- ? EXPECTED_RESULT_DESUGARED_RECORD_SUPPORT
- : EXPECTED_RESULT_DESUGARED_NO_RECORD_SUPPORT));
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
deleted file mode 100644
index 8be5a1d..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (c) 2021, 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.records;
-
-import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.desugar.LibraryFilesHelper;
-import com.android.tools.r8.utils.StringUtils;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class RecordInvokeCustomTest extends TestBase {
-
- private static final String RECORD_NAME = "RecordInvokeCustom";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
- private static final String EXPECTED_RESULT =
- StringUtils.lines(
- "%s[]",
- "true",
- "true",
- "true",
- "true",
- "true",
- "false",
- "true",
- "true",
- "false",
- "false",
- "%s[%s=Jane Doe, %s=42]");
- private static final String EXPECTED_RESULT_D8 =
- String.format(EXPECTED_RESULT, "Empty", "Person", "name", "age");
- private static final String EXPECTED_RESULT_R8 =
- String.format(EXPECTED_RESULT, "a", "b", "a", "b");
-
- private final TestParameters parameters;
-
- public RecordInvokeCustomTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters()
- .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
- .withDexRuntimes()
- .withAllApiLevelsAlsoForCf()
- .build();
- }
-
- @Test
- public void testJvm() throws Exception {
- parameters.assumeJvmTestParameters();
- testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_D8);
- }
-
- @Test
- public void testD8() throws Exception {
- testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .setMinApi(parameters)
- .compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_D8);
- }
-
- @Test
- public void testR8() throws Exception {
- parameters.assumeR8TestParameters();
- R8FullTestBuilder builder =
- testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE);
- if (parameters.isCfRuntime()) {
- builder
- .addLibraryFiles(LibraryFilesHelper.getJdk15LibraryFiles(temp))
- .compile()
- .inspect(RecordTestUtils::assertRecordsAreRecords)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_R8);
- return;
- }
- builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT_R8);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
deleted file mode 100644
index 6a63449..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2021, 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.records;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.desugar.LibraryFilesHelper;
-import com.android.tools.r8.utils.StringUtils;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class RecordReflectionTest extends TestBase {
-
- private static final String RECORD_NAME = "RecordReflection";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
- private static final String EXPECTED_RESULT =
- StringUtils.lines(
- "true",
- "[]",
- "true",
- "[java.lang.String name, int age]",
- "true",
- "[java.lang.CharSequence name, int age]",
- "[S]",
- "false",
- "null");
-
- private final TestParameters parameters;
-
- public RecordReflectionTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK17).build();
- }
-
- @Test
- public void testJvm() throws Exception {
- parameters.assumeJvmTestParameters();
- testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
-
- @Test
- public void testR8Cf() throws Exception {
- testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE)
- .addKeepAllAttributes()
- .addKeepRules("-keep class * extends java.lang.Record { private final <fields>; }")
- .addLibraryFiles(LibraryFilesHelper.getJdk15LibraryFiles(temp))
- .compile()
- .inspect(RecordTestUtils::assertRecordsAreRecords)
- .enableJVMPreview()
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
deleted file mode 100644
index 1194f76..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2021, 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.records;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.desugar.LibraryFilesHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import com.google.common.io.ByteStreams;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.junit.rules.TemporaryFolder;
-
-/**
- * Records are compiled using: third_party/openjdk/jdk-15/linux/bin/javac --release 15
- * --enable-preview path/to/file.java
- */
-public class RecordTestUtils {
-
- private static final String EXAMPLE_FOLDER = "examplesJava17";
- private static final String RECORD_FOLDER = "records";
-
- public static Path jar() {
- return Paths.get(ToolHelper.TESTS_BUILD_DIR, EXAMPLE_FOLDER, RECORD_FOLDER + ".jar");
- }
-
- public static Path[] getJdk15LibraryFiles(TemporaryFolder temp) throws Exception {
- return LibraryFilesHelper.getJdk15LibraryFiles(temp);
- }
-
- public static byte[][] getProgramData(String mainClassSimpleName) {
- byte[][] bytes = classDataFromPrefix(RECORD_FOLDER + "/" + mainClassSimpleName);
- assert bytes.length > 0 : "Did not find any program data for " + mainClassSimpleName;
- return bytes;
- }
-
- public static String getMainType(String mainClassSimpleName) {
- return RECORD_FOLDER + "." + mainClassSimpleName;
- }
-
- private static byte[][] classDataFromPrefix(String prefix) {
- Path examplePath = jar();
- if (!Files.exists(examplePath)) {
- throw new RuntimeException(
- "Could not find path "
- + examplePath
- + ". Build "
- + EXAMPLE_FOLDER
- + " by running tools/gradle.py build"
- + StringUtils.capitalize(EXAMPLE_FOLDER));
- }
- List<byte[]> result = new ArrayList<>();
- try (ZipFile zipFile = new ZipFile(examplePath.toFile())) {
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry zipEntry = entries.nextElement();
- if (zipEntry.getName().startsWith(prefix)) {
- result.add(ByteStreams.toByteArray(zipFile.getInputStream(zipEntry)));
- }
- }
- } catch (IOException e) {
- throw new RuntimeException("Could not read zip-entry from " + examplePath.toString(), e);
- }
- if (result.isEmpty()) {
- throw new RuntimeException("Did not find any class with prefix " + prefix);
- }
- return result.toArray(new byte[0][0]);
- }
-
- public static void assertRecordsAreRecords(CodeInspector inspector) {
- for (FoundClassSubject clazz : inspector.allClasses()) {
- if (clazz.getDexProgramClass().superType.toString().equals("java.lang.Record")) {
- assertTrue(clazz.getDexProgramClass().isRecord());
- }
- }
- }
-
- public static void assertNoJavaLangRecord(CodeInspector inspector, TestParameters parameters) {
- if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.V)) {
- assertFalse(inspector.clazz("java.lang.RecordTag").isPresent());
- } else {
- assertFalse(inspector.clazz("java.lang.Record").isPresent());
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
deleted file mode 100644
index e4c6be4..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2021, 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.records;
-
-import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.StringUtils;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class RecordWithMembersTest extends TestBase {
-
- private static final String RECORD_NAME = "RecordWithMembers";
- private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
- private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
- private static final String EXPECTED_RESULT =
- StringUtils.lines(
- "BobX", "43", "BobX", "43", "FelixX", "-1", "FelixX", "-1", "print", "Bob43", "extra");
-
- private final TestParameters parameters;
-
- public RecordWithMembersTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters()
- .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
- .withDexRuntimes()
- .withAllApiLevelsAlsoForCf()
- .build();
- }
-
- @Test
- public void testJvm() throws Exception {
- parameters.assumeJvmTestParameters();
- testForJvm(parameters)
- .addProgramClassFileData(PROGRAM_DATA)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
-
- @Test
- public void testD8() throws Exception {
- testForD8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .setMinApi(parameters)
- .compile()
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
-
- @Test
- public void testR8() throws Exception {
- parameters.assumeR8TestParameters();
- R8FullTestBuilder builder =
- testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .setMinApi(parameters)
- .addKeepMainRule(MAIN_TYPE);
- if (parameters.isCfRuntime()) {
- builder
- .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .compile()
- .inspect(RecordTestUtils::assertRecordsAreRecords)
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- return;
- }
- builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
index d988c22..fcd2106 100644
--- a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
+++ b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
@@ -9,10 +9,10 @@
import com.android.tools.r8.GlobalSyntheticsGenerator;
import com.android.tools.r8.GlobalSyntheticsGeneratorCommand;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java b/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java
index d37c3f8..7853976 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/annotations/CovariantReturnTypeAnnotationTransformerTest.java
@@ -4,21 +4,14 @@
package com.android.tools.r8.ir.desugar.annotations;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilation;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertTrue;
-import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.AllOf.allOf;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.AsmTestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -26,6 +19,7 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -40,6 +34,7 @@
public static final String CRTS_INNER_NAME = "CovariantReturnTypes";
public static final String CRTS_BINARY_NAME = CRT_BINARY_NAME + "$" + CRTS_INNER_NAME;
+ public static final String CRT_TYPE_NAME = CRT_BINARY_NAME.replace('/', '.');
public static final String CRTS_TYPE_NAME = CRT_BINARY_NAME.replace('/', '.');
@Parameter(0)
@@ -105,8 +100,7 @@
checkPresenceOfCovariantAnnotations(input, true);
// Version 2 of the library should always work.
- succeedsWithOption(input, true, true);
- failsCompilationByDefault(input);
+ succeedsIndependentOfFlag(input, true);
}
@Test
@@ -130,7 +124,7 @@
// If CovariantReturnType annotations are ignored, then there will be no methods with the
// signatures "L.../B;->method()L.../B;" and "L.../C;->method()L.../C;".
- failsCompilationByDefault(input);
+ failsWithOption(input, false);
}
@Test
@@ -224,24 +218,7 @@
.assertSuccessWithOutput(getExpectedOutput());
}
- private void failsCompilationByDefault(List<byte[]> input) throws Exception {
- assertFailsCompilation(
- () ->
- testForD8(parameters.getBackend())
- .addProgramClassFileData(input)
- .setMinApi(parameters)
- .compileWithExpectedDiagnostics(
- diagnostics ->
- diagnostics.assertErrorThatMatches(
- allOf(
- diagnosticType(StringDiagnostic.class),
- diagnosticMessage(
- equalTo(
- "Unexpected @CovariantReturnType annotation in non-platform"
- + " build"))))));
- }
-
- private void failsRuntimeWithOption(List<byte[]> input, boolean option) throws Exception {
+ private void failsWithOption(List<byte[]> input, boolean option) throws Exception {
testForD8(parameters.getBackend())
.addProgramClassFileData(input)
.addOptionsModification(options -> options.processCovariantReturnTypeAnnotations = option)
@@ -259,8 +236,8 @@
}
private void failsIndependentOfFlag(List<byte[]> input) throws Exception {
- failsRuntimeWithOption(input, true);
- failsRuntimeWithOption(input, false);
+ failsWithOption(input, true);
+ failsWithOption(input, false);
}
private void checkPresenceOfCovariantAnnotations(List<byte[]> input, boolean expected)
@@ -294,34 +271,34 @@
MethodSubject methodA =
clazzA.method(A.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodA, isPresent());
- assertTrue(!methodA.getMethod().isSyntheticMethod());
+ Assert.assertTrue(!methodA.getMethod().isSyntheticMethod());
MethodSubject methodB =
clazzB.method(A.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodB, isPresent());
- assertTrue(!methodB.getMethod().isSyntheticMethod());
+ Assert.assertTrue(!methodB.getMethod().isSyntheticMethod());
MethodSubject methodC =
clazzC.method(A.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodC, isPresent());
- assertTrue(!methodC.getMethod().isSyntheticMethod());
+ Assert.assertTrue(!methodC.getMethod().isSyntheticMethod());
// Check that a synthetic method has been added to class B.
MethodSubject methodB2 =
clazzB.method(B.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodB2, isPresent());
- assertTrue(methodB2.getMethod().isSyntheticMethod());
+ Assert.assertTrue(methodB2.getMethod().isSyntheticMethod());
// Check that two synthetic methods have been added to class C.
MethodSubject methodC2 =
clazzC.method(B.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodC2, isPresent());
- assertTrue(methodC2.getMethod().isSyntheticMethod());
+ Assert.assertTrue(methodC2.getMethod().isSyntheticMethod());
MethodSubject methodC3 =
clazzC.method(C.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodC3, isPresent());
- assertTrue(methodC3.getMethod().isSyntheticMethod());
+ Assert.assertTrue(methodC3.getMethod().isSyntheticMethod());
// Get classes D, E, and F.
ClassSubject clazzD = inspector.clazz(D.class.getCanonicalName());
@@ -337,34 +314,34 @@
MethodSubject methodD =
clazzD.method(D.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodD, isPresent());
- assertTrue(!methodD.getMethod().isSyntheticMethod());
+ Assert.assertTrue(!methodD.getMethod().isSyntheticMethod());
MethodSubject methodE =
clazzE.method(D.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodE, isPresent());
- assertTrue(!methodE.getMethod().isSyntheticMethod());
+ Assert.assertTrue(!methodE.getMethod().isSyntheticMethod());
MethodSubject methodF =
clazzF.method(D.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodF, isPresent());
- assertTrue(!methodF.getMethod().isSyntheticMethod());
+ Assert.assertTrue(!methodF.getMethod().isSyntheticMethod());
// Check that a synthetic method has been added to class E.
MethodSubject methodE2 =
clazzE.method(E.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodE2, isPresent());
- assertTrue(methodE2.getMethod().isSyntheticMethod());
+ Assert.assertTrue(methodE2.getMethod().isSyntheticMethod());
// Check that two synthetic methods have been added to class F.
MethodSubject methodF2 =
clazzF.method(E.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodF2, isPresent());
- assertTrue(methodF2.getMethod().isSyntheticMethod());
+ Assert.assertTrue(methodF2.getMethod().isSyntheticMethod());
MethodSubject methodF3 =
clazzF.method(F.class.getCanonicalName(), "method", Collections.emptyList());
assertThat(methodF3, isPresent());
- assertTrue(methodF3.getMethod().isSyntheticMethod());
+ Assert.assertTrue(methodF3.getMethod().isSyntheticMethod());
}
private String getExpectedOutput() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index f921cd6..8d9cc75 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -3,13 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_4_20;
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_7_0;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
@@ -60,7 +64,16 @@
.allowUnusedDontWarnJavaLangClassValue(
kotlinc.getCompilerVersion().isGreaterThan(KOTLINC_1_7_0))
.apply(configureForLibraryWithEmbeddedProguardRules())
- .compile()
+ .applyIf(kotlinc.is(KOTLINC_1_4_20), R8TestBuilder::allowDiagnosticWarningMessages)
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ if (kotlinc.is(KOTLINC_1_4_20)) {
+ diagnostics.assertWarningsMatch(
+ diagnosticMessage(
+ containsString(
+ "'META-INF/versions/9/module-info.class' already exists.")));
+ }
+ })
.assertNoErrorMessages()
.run(parameters.getRuntime(), mainClassName);
CodeInspector inspector = result.inspector();
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
index 7a54089..2149835 100644
--- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -115,7 +115,9 @@
&& kotlinParameters.getCompiler().isNot(KOTLINC_1_9_21)
&& !kotlinParameters.isKotlinDev(),
TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
- .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib)
+ .applyIf(
+ kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72),
+ KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib)
.writeToZip(foo.toPath())
.run(parameters.getRuntime(), PKG + ".SimpleReflectKt")
.assertSuccessWithOutputLines(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticStubContextRegressionTest.java b/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticStubContextRegressionTest.java
index 54f5f0c..9a56493 100644
--- a/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticStubContextRegressionTest.java
+++ b/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticStubContextRegressionTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java b/src/test/testbase/java/com/android/tools/r8/DesugarGraphTestConsumer.java
similarity index 97%
rename from src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
rename to src/test/testbase/java/com/android/tools/r8/DesugarGraphTestConsumer.java
index 541bfea..29efc40 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
+++ b/src/test/testbase/java/com/android/tools/r8/DesugarGraphTestConsumer.java
@@ -1,13 +1,12 @@
// 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.graph;
+package com.android.tools.r8;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.DesugarGraphConsumer;
import com.android.tools.r8.origin.GlobalSyntheticOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.StringUtils;
diff --git a/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticsTestingConsumer.java b/src/test/testbase/java/com/android/tools/r8/GlobalSyntheticsTestingConsumer.java
similarity index 90%
rename from src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticsTestingConsumer.java
rename to src/test/testbase/java/com/android/tools/r8/GlobalSyntheticsTestingConsumer.java
index 9f1fdaf..da3905b 100644
--- a/src/test/java/com/android/tools/r8/synthesis/globals/GlobalSyntheticsTestingConsumer.java
+++ b/src/test/testbase/java/com/android/tools/r8/GlobalSyntheticsTestingConsumer.java
@@ -1,17 +1,13 @@
// Copyright (c) 2022, 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.synthesis.globals;
+package com.android.tools.r8;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.GlobalSyntheticsConsumer;
-import com.android.tools.r8.GlobalSyntheticsResourceProvider;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.ClassReference;
import java.io.ByteArrayInputStream;
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
index 6746b89..98cb209 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
@@ -4,12 +4,16 @@
package com.android.tools.r8;
+import static com.android.tools.r8.TestBase.descriptor;
+
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dump.CompilerDump;
import com.android.tools.r8.dump.DumpOptions;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer.FieldPredicate;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableMap;
@@ -35,6 +39,19 @@
this.builder = builder;
}
+ public T addStrippedOuter(Class<?> clazz, Origin origin) throws IOException {
+ builder.addClassProgramData(
+ TestBase.transformer(clazz)
+ .removeFields(FieldPredicate.all())
+ .removeMethods(MethodPredicate.all())
+ .removeAllAnnotations()
+ .setSuper(descriptor(Object.class))
+ .setImplements()
+ .transform(),
+ origin);
+ return self();
+ }
+
@Override
public T addProgramClassFileData(Collection<byte[]> classes) {
for (byte[] clazz : classes) {
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestBuilder.java
index 5f9d323..4b18fcb 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBuilder.java
@@ -17,6 +17,8 @@
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
@@ -212,6 +214,21 @@
return self();
}
+ public T addClasspathClassesAndInnerClasses(Class<?> clazz)
+ throws InvocationTargetException, IllegalAccessException {
+ Method getNestMembers;
+ try {
+ getNestMembers = Class.class.getDeclaredMethod("getNestMembers");
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Can only use this method from Java 11 and above.");
+ }
+ Class<?>[] nestMembers = (Class<?>[]) getNestMembers.invoke(clazz);
+ Arrays.stream(nestMembers)
+ .filter(c -> c.toString().startsWith(clazz.toString()))
+ .forEach(this::addClasspathClasses);
+ return self();
+ }
+
public T addClasspathClasses(Class<?>... classes) {
return addClasspathClasses(Arrays.asList(classes));
}
diff --git a/tools/perf/chart.js b/tools/perf/chart.js
index 96c7f07..baaa33b 100644
--- a/tools/perf/chart.js
+++ b/tools/perf/chart.js
@@ -69,6 +69,9 @@
} else {
update(false, false);
}
+ document.addEventListener('keydown', e => {
+ state.handleKeyDownEvent(e, () => update(true, false));
+ });
}
function setDataProvider(theDataProvider) {
diff --git a/tools/perf/state.js b/tools/perf/state.js
index 4d0128f..ed07b39 100644
--- a/tools/perf/state.js
+++ b/tools/perf/state.js
@@ -99,6 +99,34 @@
}
}
+function handleKeyDownEvent(e, callback) {
+ if (selectedBenchmarks.size != 1) {
+ return;
+ }
+ const [selectedBenchmark] = selectedBenchmarks;
+ var benchmarkToSelect = null;
+ var previousBenchmark = null;
+ for (const benchmark of benchmarks.values()) {
+ if (previousBenchmark != null) {
+ if (e.key == 'ArrowLeft' && benchmark == selectedBenchmark) {
+ benchmarkToSelect = previousBenchmark;
+ break;
+ } else if (e.key === 'ArrowRight' && previousBenchmark == selectedBenchmark) {
+ benchmarkToSelect = benchmark;
+ break;
+ }
+ }
+ previousBenchmark = benchmark;
+ }
+ if (benchmarkToSelect != null) {
+ selectedBenchmarks.clear();
+ selectedBenchmarks.add(benchmarkToSelect);
+ document.getElementById(selectedBenchmark).checked = false;
+ document.getElementById(benchmarkToSelect).checked = true;
+ callback();
+ }
+}
+
function isLegendSelected(legend) {
return selectedLegends.has(legend);
}
@@ -111,6 +139,7 @@
selectedLegends: selectedLegends,
forEachBenchmark: forEachBenchmark,
forEachSelectedBenchmark: forEachSelectedBenchmark,
+ handleKeyDownEvent: handleKeyDownEvent,
hasLegend: hasLegend,
initializeBenchmarks: initializeBenchmarks,
initializeLegends: initializeLegends,