blob: 0758bf7dabd144a396a91dc34bf8ec2d853549b5 [file] [log] [blame]
// 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;
import static com.android.tools.r8.LibraryDesugaringTestConfiguration.Configuration.DEFAULT;
import static junit.framework.TestCase.assertNotNull;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class LibraryDesugaringTestConfiguration {
private static final String RELEASES_DIR = "third_party/openjdk/desugar_jdk_libs_releases/";
public enum Configuration {
DEFAULT(
ToolHelper.getDesugarJDKLibs(),
ToolHelper.DESUGAR_LIB_CONVERSIONS,
ToolHelper.getDesugarLibJsonForTesting()),
DEFAULT_JDK11(
Paths.get("third_party/openjdk/desugar_jdk_libs_11/desugar_jdk_libs.jar"),
ToolHelper.DESUGAR_LIB_CONVERSIONS,
Paths.get("src/library_desugar/jdk11/desugar_jdk_libs.json")),
RELEASED_1_0_9("1.0.9"),
RELEASED_1_0_10("1.0.10"),
RELEASED_1_1_0("1.1.0"),
RELEASED_1_1_1("1.1.1"),
RELEASED_1_1_5("1.1.5");
private final Path desugarJdkLibs;
private final Path customConversions;
private final Path configuration;
Configuration(Path desugarJdkLibs, Path customConversions, Path configuration) {
this.desugarJdkLibs = desugarJdkLibs;
this.customConversions = customConversions;
this.configuration = configuration;
}
Configuration(String version) {
this(
Paths.get(RELEASES_DIR, version, "desugar_jdk_libs.jar"),
Paths.get(RELEASES_DIR, version, "desugar_jdk_libs_configuration.jar"),
Paths.get(RELEASES_DIR, version, "desugar.json"));
}
public static List<Configuration> getReleased() {
return ImmutableList.of(
RELEASED_1_0_9, RELEASED_1_0_10, RELEASED_1_1_0, RELEASED_1_1_1, RELEASED_1_1_5);
}
}
private final AndroidApiLevel minApiLevel;
private final Path desugarJdkLibs;
private final Path customConversions;
private final List<StringResource> desugaredLibrarySpecificationResources;
private final boolean withKeepRuleConsumer;
private final KeepRuleConsumer keepRuleConsumer;
private final CompilationMode mode;
private final boolean addRunClassPath;
public static final LibraryDesugaringTestConfiguration DISABLED =
new LibraryDesugaringTestConfiguration();
private LibraryDesugaringTestConfiguration() {
this.minApiLevel = null;
this.desugarJdkLibs = null;
this.customConversions = null;
this.keepRuleConsumer = null;
this.withKeepRuleConsumer = false;
this.desugaredLibrarySpecificationResources = null;
this.mode = null;
this.addRunClassPath = false;
}
private LibraryDesugaringTestConfiguration(
AndroidApiLevel minApiLevel,
Path desugarJdkLibs,
Path customConversions,
List<StringResource> desugaredLibrarySpecificationResources,
boolean withKeepRuleConsumer,
KeepRuleConsumer keepRuleConsumer,
CompilationMode mode,
boolean addRunClassPath) {
this.minApiLevel = minApiLevel;
this.desugarJdkLibs = desugarJdkLibs;
this.customConversions = customConversions;
this.desugaredLibrarySpecificationResources = desugaredLibrarySpecificationResources;
this.withKeepRuleConsumer = withKeepRuleConsumer;
this.keepRuleConsumer = keepRuleConsumer;
this.mode = mode;
this.addRunClassPath = addRunClassPath;
}
public static class Builder {
AndroidApiLevel minApiLevel;
private Path desugarJdkLibs;
private Path customConversions;
private final List<StringResource> desugaredLibrarySpecificationResources = new ArrayList<>();
boolean withKeepRuleConsumer = false;
KeepRuleConsumer keepRuleConsumer;
private CompilationMode mode = CompilationMode.DEBUG;
boolean addRunClassPath = true;
private Builder() {}
public Builder setMinApi(AndroidApiLevel minApiLevel) {
this.minApiLevel = minApiLevel;
return this;
}
public Builder setConfiguration(Configuration configuration) {
desugarJdkLibs = configuration.desugarJdkLibs;
customConversions = configuration.customConversions;
desugaredLibrarySpecificationResources.clear();
desugaredLibrarySpecificationResources.add(
StringResource.fromFile(configuration.configuration));
return this;
}
public Builder withKeepRuleConsumer() {
withKeepRuleConsumer = true;
return this;
}
public Builder setKeepRuleConsumer(KeepRuleConsumer keepRuleConsumer) {
withKeepRuleConsumer = false;
if (keepRuleConsumer == null) {
this.keepRuleConsumer = null;
} else {
this.keepRuleConsumer = keepRuleConsumer;
}
return this;
}
public Builder addDesugaredLibraryConfiguration(StringResource desugaredLibrarySpecification) {
desugaredLibrarySpecificationResources.add(desugaredLibrarySpecification);
return this;
}
public Builder setMode(CompilationMode mode) {
this.mode = mode;
return this;
}
public Builder dontAddRunClasspath() {
addRunClassPath = false;
return this;
}
public LibraryDesugaringTestConfiguration build() {
if (desugaredLibrarySpecificationResources.isEmpty()) {
desugaredLibrarySpecificationResources.add(
StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
}
if (withKeepRuleConsumer) {
this.keepRuleConsumer = createKeepRuleConsumer(minApiLevel);
}
return new LibraryDesugaringTestConfiguration(
minApiLevel,
desugarJdkLibs != null ? desugarJdkLibs : DEFAULT.desugarJdkLibs,
customConversions != null ? customConversions : DEFAULT.customConversions,
desugaredLibrarySpecificationResources,
withKeepRuleConsumer,
keepRuleConsumer,
mode,
addRunClassPath);
}
}
public static Builder builder() {
return new Builder();
}
public static LibraryDesugaringTestConfiguration forApiLevel(AndroidApiLevel apiLevel) {
return LibraryDesugaringTestConfiguration.builder().setMinApi(apiLevel).build();
}
public boolean isEnabled() {
return this != DISABLED;
}
public boolean isAddRunClassPath() {
return addRunClassPath;
}
public void configure(D8Command.Builder builder) {
if (!isEnabled()) {
return;
}
if (keepRuleConsumer != null) {
builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
}
desugaredLibrarySpecificationResources.forEach(builder::addDesugaredLibraryConfiguration);
}
public void configure(R8Command.Builder builder) {
if (!isEnabled()) {
return;
}
if (keepRuleConsumer != null) {
builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
}
desugaredLibrarySpecificationResources.forEach(builder::addDesugaredLibraryConfiguration);
}
public Path buildDesugaredLibrary(TestState state) {
String generatedKeepRules = null;
if (withKeepRuleConsumer) {
if (keepRuleConsumer instanceof PresentKeepRuleConsumer) {
generatedKeepRules = keepRuleConsumer.get();
assertNotNull(generatedKeepRules);
} else {
assertThat(keepRuleConsumer, instanceOf(AbsentKeepRuleConsumer.class));
}
}
String finalGeneratedKeepRules = generatedKeepRules;
try {
assert desugaredLibrarySpecificationResources.size() == 1 : "There can be only one";
return L8TestBuilder.create(minApiLevel, Backend.DEX, state)
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.setDesugarJDKLibs(desugarJdkLibs)
.setDesugarJDKLibsConfiguration(customConversions)
.setDesugaredLibraryConfiguration(desugaredLibrarySpecificationResources.get(0))
.applyIf(
mode == CompilationMode.RELEASE,
builder -> {
if (finalGeneratedKeepRules != null && !finalGeneratedKeepRules.trim().isEmpty()) {
builder.addGeneratedKeepRules(finalGeneratedKeepRules);
}
},
L8TestBuilder::setDebug)
.compile()
.writeToZip();
} catch (CompilationFailedException | ExecutionException | IOException e) {
throw new RuntimeException(e);
}
}
public KeepRuleConsumer getKeepRuleConsumer() {
return keepRuleConsumer;
}
public static KeepRuleConsumer createKeepRuleConsumer(TestParameters parameters) {
return createKeepRuleConsumer(parameters.getApiLevel());
}
private static KeepRuleConsumer createKeepRuleConsumer(AndroidApiLevel apiLevel) {
return new PresentKeepRuleConsumer();
}
public static class PresentKeepRuleConsumer implements KeepRuleConsumer {
StringBuilder stringBuilder = new StringBuilder();
String result = null;
@Override
public void accept(String string, DiagnosticsHandler handler) {
assert stringBuilder != null;
assert result == null;
stringBuilder.append(string);
}
@Override
public void finished(DiagnosticsHandler handler) {
assert stringBuilder != null;
assert result == null;
result = stringBuilder.toString();
stringBuilder = null;
}
public String get() {
// TODO(clement): remove that branch once StringConsumer has finished again.
if (stringBuilder != null) {
finished(null);
}
assert stringBuilder == null;
assert result != null;
return result;
}
}
public static class AbsentKeepRuleConsumer implements KeepRuleConsumer {
public String get() {
return null;
}
@Override
public void accept(String string, DiagnosticsHandler handler) {
throw new Unreachable("No desugaring on high API levels");
}
@Override
public void finished(DiagnosticsHandler handler) {
throw new Unreachable("No desugaring on high API levels");
}
}
}