blob: eebc7250d0b15ac1dad60667460b2f57865c953f [file] [log] [blame]
// 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.desugaredlibrary;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_MINIMAL;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8AndAll3Jdk11;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMember;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.MemberAnnotation;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClassesGenerator;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/** This test validates that anything supported at API N-1 is supported at API N. */
@RunWith(Parameterized.class)
public class PartialDesugaringTest extends DesugaredLibraryTestBase {
LibraryDesugaringSpecification librarySpecification;
@Parameters(name = "{0}, spec: {1}")
public static List<Object[]> data() {
return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8AndAll3Jdk11());
}
public PartialDesugaringTest(
TestParameters parameters, LibraryDesugaringSpecification librarySpecification) {
assert parameters.isNoneRuntime();
this.librarySpecification = librarySpecification;
}
private static List<AndroidApiLevel> getRelevantApiLevels() {
// B is implicit - everything is supported on B.
return ImmutableList.of(
AndroidApiLevel.K,
AndroidApiLevel.L,
AndroidApiLevel.M,
AndroidApiLevel.N,
AndroidApiLevel.O,
AndroidApiLevel.P,
AndroidApiLevel.Q,
AndroidApiLevel.R,
AndroidApiLevel.S,
AndroidApiLevel.T,
AndroidApiLevel.U);
}
// TODO(b/268425188): Fix remaining failures.
private static final Set<String> FAILURES_STREAM =
ImmutableSet.of(
"java.util.stream.Stream java.util.stream.Stream.takeWhile(java.util.function.Predicate)",
"java.util.stream.Stream"
+ " java.util.stream.Stream.dropWhile(java.util.function.Predicate)");
private static final Set<String> FAILURES_NUMBER_STREAM =
ImmutableSet.of(
"java.util.stream.IntStream"
+ " java.util.stream.IntStream.dropWhile(java.util.function.IntPredicate)",
"java.util.stream.LongStream"
+ " java.util.stream.LongStream.dropWhile(java.util.function.LongPredicate)",
"java.util.stream.DoubleStream"
+ " java.util.stream.DoubleStream.takeWhile(java.util.function.DoublePredicate)",
"java.util.stream.IntStream"
+ " java.util.stream.IntStream.takeWhile(java.util.function.IntPredicate)",
"java.util.stream.LongStream"
+ " java.util.stream.LongStream.takeWhile(java.util.function.LongPredicate)",
"java.util.stream.DoubleStream"
+ " java.util.stream.DoubleStream.dropWhile(java.util.function.DoublePredicate)");
private static final Set<String> FAILURES_FILE_STORE =
ImmutableSet.of(
// FileStore.getBlockSize() was added in 33.
"long java.nio.file.FileStore.getBlockSize()");
private static final Set<String> FAILURES_SUMMARY_STATISTICS =
ImmutableSet.of(
"void java.util.LongSummaryStatistics.<init>(long, long, long, long)",
"void java.util.IntSummaryStatistics.<init>(long, int, int, long)");
// For some reason, in Android T, the other constructor were added but not this one...
private static final Set<String> FAILURES_DOUBLE_SUMMARY_STATISTICS =
ImmutableSet.of(
"void java.util.DoubleSummaryStatistics.<init>(long, double, double, double)");
private static final Set<String> FAILURES_TO_ARRAY =
ImmutableSet.of(
// See b/266401747: Desugaring is disabled.
"java.lang.Object[] java.util.Collection.toArray(java.util.function.IntFunction)");
private static final Set<String> FAILURES_ERA =
ImmutableSet.of(
// This fails on Java 8 desugared library due to missing covariant return type.
// The method is present on platform from 33 but not in android.jar...
"java.time.chrono.IsoEra java.time.LocalDate.getEra()");
private static final Set<String> FAILURES_CHRONOLOGY =
ImmutableSet.of(
"long java.time.chrono.Chronology.epochSecond(int, int, int, int, int, int,"
+ " java.time.ZoneOffset)",
"long java.time.chrono.Chronology.epochSecond(java.time.chrono.Era, int, int, int, int,"
+ " int, int, java.time.ZoneOffset)",
"long java.time.chrono.IsoChronology.epochSecond(int, int, int, int, int, int,"
+ " java.time.ZoneOffset)");
private static final Set<String> FAILURES_DATE_TIME_BUILDER =
ImmutableSet.of(
"java.time.format.DateTimeFormatterBuilder"
+ " java.time.format.DateTimeFormatterBuilder.appendGenericZoneText(java.time.format.TextStyle)",
"java.time.format.DateTimeFormatterBuilder"
+ " java.time.format.DateTimeFormatterBuilder.appendGenericZoneText(java.time.format.TextStyle,"
+ " java.util.Set)");
private static final Set<String> FAILURES_JAPANESE_ERA =
ImmutableSet.of("Field java.time.chrono.JapaneseEra java.time.chrono.JapaneseEra.REIWA");
@Test
public void test() throws Exception {
SupportedClasses supportedClasses =
new SupportedClassesGenerator(
new InternalOptions(), ToolHelper.getAndroidJar(AndroidApiLevel.U))
.run(librarySpecification.getDesugarJdkLibs(), librarySpecification.getSpecification());
for (AndroidApiLevel api : getRelevantApiLevels()) {
Set<DexMethod> localMethodFailures = Sets.newIdentityHashSet();
Set<DexField> localFieldFailures = Sets.newIdentityHashSet();
supportedClasses.forEachClass(
supportedClass -> {
supportedClass.forEachMethodAndAnnotation(
(method, annotation) -> {
if (missingFromRange(api, annotation)) {
localMethodFailures.add(method.getReference());
}
});
supportedClass.forEachFieldAndAnnotation(
(field, annotation) -> {
if (missingFromRange(api, annotation)) {
localFieldFailures.add(field.getReference());
}
});
});
assertStringEqualsAtApi(localFieldFailures, getExpectedFieldFailures(api), api);
assertStringEqualsAtApi(localMethodFailures, getExpectedMethodFailures(api), api);
}
}
private void assertStringEqualsAtApi(
Set<? extends DexMember<?, ?>> found, Set<String> expected, AndroidApiLevel api) {
Set<String> apiFailuresString =
found.stream().map(DexMember::toString).collect(Collectors.toSet());
assertEquals("Failure for api " + api, expected, apiFailuresString);
}
private boolean missingFromRange(AndroidApiLevel api, MemberAnnotation annotation) {
if (annotation != null && annotation.isUnsupportedInMinApiRange()) {
return api.getLevel() >= annotation.getMinRange()
&& api.getLevel() <= annotation.getMaxRange();
}
return false;
}
private Set<String> getExpectedFieldFailures(AndroidApiLevel api) {
if (librarySpecification == JDK11 || librarySpecification == JDK11_PATH) {
if (api.isGreaterThanOrEqualTo(AndroidApiLevel.O) && api.isLessThan(AndroidApiLevel.R)) {
return FAILURES_JAPANESE_ERA;
}
}
return ImmutableSet.of();
}
private Set<String> getExpectedMethodFailures(AndroidApiLevel api) {
Set<String> expectedFailures = new HashSet<>();
boolean jdk11NonMinimal = librarySpecification != JDK8 && librarySpecification != JDK11_MINIMAL;
if (jdk11NonMinimal && api.isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
expectedFailures.addAll(FAILURES_NUMBER_STREAM);
if (api.isLessThan(AndroidApiLevel.U)) {
expectedFailures.addAll(FAILURES_STREAM);
expectedFailures.addAll(FAILURES_DOUBLE_SUMMARY_STATISTICS);
}
if (api.isLessThan(AndroidApiLevel.T)) {
expectedFailures.addAll(FAILURES_SUMMARY_STATISTICS);
}
}
if (librarySpecification == JDK11_PATH
&& api.isGreaterThanOrEqualTo(AndroidApiLevel.O)
&& api.isLessThan(AndroidApiLevel.T)) {
expectedFailures.addAll(FAILURES_FILE_STORE);
}
if (librarySpecification != JDK11_MINIMAL
&& api.isGreaterThanOrEqualTo(AndroidApiLevel.N)
&& api.isLessThan(AndroidApiLevel.T)) {
expectedFailures.addAll(FAILURES_TO_ARRAY);
}
if (jdk11NonMinimal
&& api.isGreaterThanOrEqualTo(AndroidApiLevel.O)
&& api.isLessThan(AndroidApiLevel.U)) {
expectedFailures.addAll(FAILURES_CHRONOLOGY);
expectedFailures.addAll(FAILURES_DATE_TIME_BUILDER);
}
if (librarySpecification == JDK8 && api.isGreaterThanOrEqualTo(AndroidApiLevel.O)) {
expectedFailures.addAll(FAILURES_ERA);
}
return expectedFailures;
}
}