Introduce DesugaredMethodsList command
Bug: b/302055774
Change-Id: If42e3c3402ba643a2d6f5bf3da07dda8e4e51cd5
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsList.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsList.java
index 731942c..ee0f728 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsList.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsList.java
@@ -13,9 +13,11 @@
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.StringResource;
+import com.android.tools.r8.Version;
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.Paths;
import java.util.Collection;
import java.util.List;
@@ -38,8 +40,26 @@
this.outputConsumer = outputConsumer;
}
+ public static void run(DesugaredMethodsListCommand command) throws IOException {
+ if (command.isHelp()) {
+ System.out.println(DesugaredMethodsListCommand.getUsageMessage());
+ return;
+ }
+ if (command.isVersion()) {
+ System.out.println("DesugaredMethodsList " + Version.getVersionString());
+ return;
+ }
+ new DesugaredMethodsList(
+ command.getMinApi(),
+ command.getDesugarLibrarySpecification(),
+ command.getDesugarLibraryImplementation(),
+ command.getOutputConsumer(),
+ command.getLibrary())
+ .run();
+ }
+
@Override
- public AndroidApiLevel run() throws Exception {
+ public AndroidApiLevel run() throws IOException {
AndroidApiLevel compilationLevel =
desugaredLibrarySpecification.getRequiredCompilationApiLevel();
SupportedClasses supportedMethods =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java
new file mode 100644
index 0000000..948ea0c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/DesugaredMethodsListCommand.java
@@ -0,0 +1,240 @@
+// 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.ir.desugar.desugaredlibrary.lint;
+
+import com.android.tools.r8.ArchiveClassFileProvider;
+import com.android.tools.r8.ArchiveProgramResourceProvider;
+import com.android.tools.r8.ClassFileResourceProvider;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.ParseFlagInfo;
+import com.android.tools.r8.ParseFlagInfoImpl;
+import com.android.tools.r8.ParseFlagPrinter;
+import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.origin.Origin;
+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.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Keep
+public class DesugaredMethodsListCommand {
+
+ private final boolean help;
+ private final boolean version;
+ private final int minApi;
+ private final StringResource desugarLibrarySpecification;
+ private final Collection<ProgramResourceProvider> desugarLibraryImplementation;
+ private final StringConsumer outputConsumer;
+ private final Collection<ClassFileResourceProvider> library;
+
+ DesugaredMethodsListCommand(
+ int minApi,
+ StringResource desugarLibrarySpecification,
+ Collection<ProgramResourceProvider> desugarLibraryImplementation,
+ StringConsumer outputConsumer,
+ Collection<ClassFileResourceProvider> library) {
+ this.help = false;
+ this.version = false;
+ this.minApi = minApi;
+ this.desugarLibrarySpecification = desugarLibrarySpecification;
+ this.desugarLibraryImplementation = desugarLibraryImplementation;
+ this.outputConsumer = outputConsumer;
+ this.library = library;
+ }
+
+ DesugaredMethodsListCommand(boolean help, boolean version) {
+ this.help = help;
+ this.version = version;
+ this.minApi = -1;
+ this.desugarLibrarySpecification = null;
+ this.desugarLibraryImplementation = null;
+ this.outputConsumer = null;
+ this.library = null;
+ }
+
+ public int getMinApi() {
+ return minApi;
+ }
+
+ public StringResource getDesugarLibrarySpecification() {
+ return desugarLibrarySpecification;
+ }
+
+ public Collection<ProgramResourceProvider> getDesugarLibraryImplementation() {
+ return desugarLibraryImplementation;
+ }
+
+ public StringConsumer getOutputConsumer() {
+ return outputConsumer;
+ }
+
+ public Collection<ClassFileResourceProvider> getLibrary() {
+ return library;
+ }
+
+ public boolean isHelp() {
+ return help;
+ }
+
+ public boolean isVersion() {
+ return version;
+ }
+
+ public static String getUsageMessage() {
+ StringBuilder builder = new StringBuilder();
+ StringUtils.appendLines(builder, "Usage: desugaredmethods [options] where options are:");
+ new ParseFlagPrinter()
+ .addFlags(ImmutableList.copyOf(DesugaredMethodsListCommandParser.getFlags()))
+ .appendLinesToBuilder(builder);
+ return builder.toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Keep
+ public static class Builder {
+
+ private int minApi = AndroidApiLevel.B.getLevel();
+ private StringResource desugarLibrarySpecification = null;
+ private Collection<ProgramResourceProvider> desugarLibraryImplementation = new ArrayList<>();
+ private StringConsumer outputConsumer;
+ private Collection<ClassFileResourceProvider> library = new ArrayList<>();
+
+ private boolean help = false;
+ private boolean version = false;
+
+ public Builder setMinApi(int minApi) {
+ this.minApi = minApi;
+ return this;
+ }
+
+ public Builder setDesugarLibrarySpecification(StringResource desugarLibrarySpecification) {
+ this.desugarLibrarySpecification = desugarLibrarySpecification;
+ return this;
+ }
+
+ public Builder setOutputConsumer(StringConsumer outputConsumer) {
+ this.outputConsumer = outputConsumer;
+ return this;
+ }
+
+ public Builder addDesugarLibraryImplementation(
+ ProgramResourceProvider programResourceProvider) {
+ desugarLibraryImplementation.add(programResourceProvider);
+ return this;
+ }
+
+ public Builder addLibrary(ClassFileResourceProvider classFileResourceProvider) {
+ library.add(classFileResourceProvider);
+ return this;
+ }
+
+ public Builder setHelp() {
+ this.help = true;
+ return this;
+ }
+
+ public Builder setVersion() {
+ this.version = true;
+ return this;
+ }
+
+ public DesugaredMethodsListCommand build() {
+ // The min-api level defaults to 1, it's always present.
+ // If desugarLibraryImplementation is empty, this generates only the backported method list.
+
+ if (help || version) {
+ return new DesugaredMethodsListCommand(help, version);
+ }
+
+ if (desugarLibrarySpecification != null && library.isEmpty()) {
+ throw new CompilationError("With desugared library configuration a library is required");
+ }
+
+ if (!desugarLibraryImplementation.isEmpty() && desugarLibrarySpecification == null) {
+ throw new CompilationError(
+ "desugarLibrarySpecification is required when desugared library implementation is"
+ + " present.");
+ }
+
+ if (outputConsumer == null) {
+ outputConsumer =
+ new StringConsumer() {
+ @Override
+ public void accept(String string, DiagnosticsHandler handler) {
+ System.out.println(string);
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {}
+ };
+ }
+ return new DesugaredMethodsListCommand(
+ minApi,
+ desugarLibrarySpecification,
+ desugarLibraryImplementation,
+ outputConsumer,
+ library);
+ }
+ }
+
+ public static class DesugaredMethodsListCommandParser {
+
+ static List<ParseFlagInfo> getFlags() {
+ return ImmutableList.<ParseFlagInfo>builder()
+ .add(ParseFlagInfoImpl.getOutput())
+ .add(ParseFlagInfoImpl.getLib())
+ .add(ParseFlagInfoImpl.getMinApi())
+ .add(ParseFlagInfoImpl.getVersion("DesugaredMethods"))
+ .add(ParseFlagInfoImpl.getHelp())
+ .add(ParseFlagInfoImpl.getDesugaredLib())
+ .add(
+ ParseFlagInfoImpl.flag1(
+ "--desugared-lib-jar", "<file>", "Specify desugared library jar."))
+ .build();
+ }
+
+ public DesugaredMethodsListCommand parse(String[] args, Origin origin) throws IOException {
+ DesugaredMethodsListCommand.Builder builder = DesugaredMethodsListCommand.builder();
+ for (int i = 0; i < args.length; i += 2) {
+ String arg = args[i].trim();
+ if (arg.length() == 0) {
+ continue;
+ } else if (arg.equals("--help")) {
+ builder.setHelp();
+ continue;
+ } else if (arg.equals("--version")) {
+ builder.setVersion();
+ continue;
+ }
+ String argValue = args[i + 1].trim();
+ if (arg.equals("--min-api")) {
+ builder.setMinApi(Integer.parseInt(argValue));
+ } else if (arg.equals("--desugared-lib")) {
+ builder.setDesugarLibrarySpecification(StringResource.fromFile(Paths.get(argValue)));
+ } else if (arg.equals("--desugared-lib-jar")) {
+ builder.addDesugarLibraryImplementation(
+ ArchiveProgramResourceProvider.fromArchive(Paths.get(argValue)));
+ } else if (arg.equals("--output")) {
+ builder.setOutputConsumer(new StringConsumer.FileConsumer(Paths.get(argValue)));
+ } else if (arg.equals("--lib")) {
+ builder.addLibrary(new ArchiveClassFileProvider(Paths.get(argValue)));
+ }
+ }
+
+ return builder.build();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateDesugaredLibraryLintFiles.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateDesugaredLibraryLintFiles.java
index defba4b..0f7c141 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateDesugaredLibraryLintFiles.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateDesugaredLibraryLintFiles.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -45,7 +46,7 @@
private Path lintFile(
AndroidApiLevel compilationApiLevel, AndroidApiLevel minApiLevel, String extension)
- throws Exception {
+ throws IOException {
Path directory = output.resolve("compile_api_level_" + compilationApiLevel.getLevel());
Files.createDirectories(directory);
return Paths.get(
@@ -59,7 +60,7 @@
AndroidApiLevel compilationApiLevel,
AndroidApiLevel minApiLevel,
SupportedClasses supportedClasses)
- throws Exception {
+ throws IOException {
// Build a plain text file with the desugared APIs.
List<String> desugaredApisSignatures = new ArrayList<>();
@@ -114,7 +115,7 @@
AndroidApiLevel compilationApiLevel,
AndroidApiLevel minApiLevel,
List<String> desugaredApisSignatures)
- throws Exception {
+ throws IOException {
FileUtils.writeTextFile(
lintFile(compilationApiLevel, minApiLevel, ".txt"), desugaredApisSignatures);
}