Generate method lists for lint based on library desugar configuration
The generated files are included in the maven artifact with library
desugar configuration.
Bug: 134732760
Change-Id: I3bf8c43ef8e3004ba802d3584a636e31d4ded1ed
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
new file mode 100644
index 0000000..2c63a69
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -0,0 +1,335 @@
+// 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;
+
+import com.android.tools.r8.cf.code.CfConstNull;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexLibraryClass;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.jar.CfApplicationWriter;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.Sets;
+import java.io.File;
+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.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+
+public class GenerateLintFiles {
+
+ private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
+
+ private final DexItemFactory factory = new DexItemFactory();
+ private final Reporter reporter = new Reporter();
+ private final InternalOptions options = new InternalOptions(factory, reporter);
+
+ private final DesugaredLibraryConfiguration desugaredLibraryConfiguration;
+ private final String outputDirectory;
+
+ private final Set<DexMethod> parallelMethods = Sets.newIdentityHashSet();
+
+ private GenerateLintFiles(String desugarConfigurationPath, String outputDirectory) {
+ this.desugaredLibraryConfiguration =
+ readDesugaredLibraryConfiguration(desugarConfigurationPath);
+ this.outputDirectory =
+ outputDirectory.endsWith("/") ? outputDirectory : outputDirectory + File.separator;
+
+ DexType streamType = factory.createType(factory.createString("Ljava/util/stream/Stream;"));
+ DexMethod parallelMethod =
+ factory.createMethod(
+ factory.collectionType,
+ factory.createProto(streamType),
+ factory.createString("parallelStream"));
+ parallelMethods.add(parallelMethod);
+ for (String typePrefix : new String[] {"Base", "Double", "Int", "Long"}) {
+ streamType =
+ factory.createType(factory.createString("Ljava/util/stream/" + typePrefix + "Stream;"));
+ parallelMethod =
+ factory.createMethod(
+ streamType, factory.createProto(streamType), factory.createString("parallel"));
+ parallelMethods.add(parallelMethod);
+ }
+ }
+
+ private static Path getAndroidJarPath(AndroidApiLevel apiLevel) {
+ String jar = String.format(ANDROID_JAR_PATTERN, apiLevel.getLevel());
+ return Paths.get(jar);
+ }
+
+ private DesugaredLibraryConfiguration readDesugaredLibraryConfiguration(
+ String desugarConfigurationPath) {
+ return new DesugaredLibraryConfigurationParser(
+ factory, reporter, false, AndroidApiLevel.B.getLevel())
+ .parse(StringResource.fromFile(Paths.get(desugarConfigurationPath)));
+ }
+
+ private CfCode buildEmptyThrowingCfCode(DexMethod method) {
+ CfInstruction insn[] = {new CfConstNull(), new CfThrow()};
+ return new CfCode(
+ method.holder,
+ 1,
+ method.proto.parameters.size() + 1,
+ Arrays.asList(insn),
+ Collections.emptyList(),
+ Collections.emptyList());
+ }
+
+ private void addMethodsToHeaderJar(
+ DexApplication.Builder builder, DexClass clazz, List<DexEncodedMethod> methods) {
+ if (methods.size() == 0) {
+ return;
+ }
+
+ List<DexEncodedMethod> directMethods = new ArrayList<>();
+ List<DexEncodedMethod> virtualMethods = new ArrayList<>();
+ for (DexEncodedMethod method : methods) {
+ assert method.method.holder == clazz.type;
+ CfCode code = null;
+ if (!method.accessFlags.isAbstract() /*&& !method.accessFlags.isNative()*/) {
+ code = buildEmptyThrowingCfCode(method.method);
+ }
+ DexEncodedMethod throwingMethod =
+ new DexEncodedMethod(
+ method.method,
+ method.accessFlags,
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ code,
+ 50);
+ if (method.accessFlags.isStatic()) {
+ directMethods.add(throwingMethod);
+ } else {
+ virtualMethods.add(throwingMethod);
+ }
+ }
+
+ DexEncodedMethod[] directMethodsArray = new DexEncodedMethod[directMethods.size()];
+ DexEncodedMethod[] virtualMethodsArray = new DexEncodedMethod[virtualMethods.size()];
+ directMethods.toArray(directMethodsArray);
+ virtualMethods.toArray(virtualMethodsArray);
+ builder.addProgramClass(
+ new DexProgramClass(
+ clazz.type,
+ null,
+ Origin.unknown(),
+ clazz.accessFlags,
+ clazz.superType,
+ clazz.interfaces,
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ directMethodsArray,
+ virtualMethodsArray,
+ false));
+ }
+
+ private Map<DexClass, List<DexEncodedMethod>> collectSupportedMethods(
+ AndroidApiLevel compilationApiLevel, Predicate<DexEncodedMethod> supported)
+ throws IOException, ExecutionException {
+
+ // Read the android.jar for the compilation API level.
+ AndroidApp library =
+ AndroidApp.builder().addLibraryFiles(getAndroidJarPath(compilationApiLevel)).build();
+ DirectMappedDexApplication dexApplication =
+ new ApplicationReader(library, options, new Timing()).read().toDirect();
+
+ // collect all the methods that the library desugar configuration adds support for.
+ Map<DexClass, List<DexEncodedMethod>> supportedMethods = new LinkedHashMap<>();
+ for (DexLibraryClass clazz : dexApplication.libraryClasses()) {
+ String className = clazz.toSourceString();
+ // All the methods with the rewritten prefix are supported.
+ for (String prefix : desugaredLibraryConfiguration.getRewritePrefix().keySet()) {
+ if (clazz.accessFlags.isPublic() && className.startsWith(prefix)) {
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (supported.test(method)) {
+ supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
+ }
+ }
+ }
+ }
+
+ // All retargeted methods are supported.
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (desugaredLibraryConfiguration
+ .getRetargetCoreLibMember()
+ .keySet()
+ .contains(method.method.name)) {
+ if (desugaredLibraryConfiguration
+ .getRetargetCoreLibMember()
+ .get(method.method.name)
+ .containsKey(clazz.type)) {
+ if (supported.test(method)) {
+ supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
+ }
+ }
+ }
+ }
+ // All emulated interfaces methods are supported.
+ if (desugaredLibraryConfiguration.getEmulateLibraryInterface().containsKey(clazz.type)) {
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (supported.test(method)) {
+ supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
+ }
+ }
+ }
+ }
+
+ return supportedMethods;
+ }
+
+ private String lintBaseFileName(
+ AndroidApiLevel compilationApiLevel, AndroidApiLevel minApiLevel) {
+ return "desugared_apis_" + compilationApiLevel.getLevel() + "_" + minApiLevel.getLevel();
+ }
+
+ private Path lintFile(
+ AndroidApiLevel compilationApiLevel, AndroidApiLevel minApiLevel, String extension)
+ throws Exception {
+ Path directory =
+ Paths.get(outputDirectory + "compile_api_level_" + compilationApiLevel.getLevel());
+ Files.createDirectories(directory);
+ return Paths.get(
+ directory
+ + File.separator
+ + lintBaseFileName(compilationApiLevel, minApiLevel)
+ + extension);
+ }
+
+ private void writeLintFiles(
+ AndroidApiLevel compilationApiLevel,
+ AndroidApiLevel minApiLevel,
+ Map<DexClass, List<DexEncodedMethod>> supportedMethods)
+ throws Exception {
+ // Build a plain text file with the desugared APIs.
+ List<String> desugaredApisSignatures = new ArrayList<>();
+
+ DexApplication.Builder builder = DexApplication.builder(options, new Timing());
+ supportedMethods.forEach(
+ (clazz, methods) -> {
+ String classBinaryName =
+ DescriptorUtils.getClassBinaryNameFromDescriptor(clazz.type.descriptor.toString());
+ for (DexEncodedMethod method : methods) {
+ desugaredApisSignatures.add(
+ classBinaryName
+ + '/'
+ + method.method.name
+ + method.method.proto.toDescriptorString());
+ }
+
+ addMethodsToHeaderJar(builder, clazz, methods);
+ });
+ DexApplication app = builder.build();
+
+ // Write a plain text file with the desugared APIs.
+ FileUtils.writeTextFile(
+ lintFile(compilationApiLevel, minApiLevel, ".txt"), desugaredApisSignatures);
+
+ // Write a header jar with the desugared APIs.
+ AppInfo appInfo = new AppInfo(app);
+ AppView<?> appView = AppView.createForD8(appInfo, options);
+ CfApplicationWriter writer =
+ new CfApplicationWriter(
+ builder.build(),
+ appView,
+ options,
+ options.getMarker(Tool.L8),
+ GraphLense.getIdentityLense(),
+ NamingLens.getIdentityLens(),
+ null);
+ ClassFileConsumer consumer =
+ new ClassFileConsumer.ArchiveConsumer(
+ lintFile(compilationApiLevel, minApiLevel, FileUtils.JAR_EXTENSION));
+ writer.write(consumer, ThreadUtils.getExecutorService(options));
+ consumer.finished(options.reporter);
+ }
+
+ private void generateLintFiles(
+ AndroidApiLevel compilationApiLevel,
+ Predicate<AndroidApiLevel> generateForThisMinApiLevel,
+ BiPredicate<AndroidApiLevel, DexEncodedMethod> supportedForMinApiLevel)
+ throws Exception {
+ for (AndroidApiLevel value : AndroidApiLevel.values()) {
+ if (!generateForThisMinApiLevel.test(value)) {
+ continue;
+ }
+
+ Map<DexClass, List<DexEncodedMethod>> supportedMethods =
+ collectSupportedMethods(
+ compilationApiLevel, (method -> supportedForMinApiLevel.test(value, method)));
+ writeLintFiles(compilationApiLevel, value, supportedMethods);
+ }
+ }
+
+ private void run() throws Exception {
+ // Run over all the API levels that the desugared library can be compiled with.
+ for (int apiLevel = AndroidApiLevel.Q.getLevel();
+ apiLevel >= desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel();
+ apiLevel--) {
+ System.out.println("Generating lint files for compile API " + apiLevel);
+ generateLintFiles(
+ AndroidApiLevel.getAndroidApiLevel(apiLevel),
+ minApiLevel -> minApiLevel == AndroidApiLevel.L || minApiLevel == AndroidApiLevel.B,
+ (minApiLevel, method) -> {
+ assert minApiLevel == AndroidApiLevel.L || minApiLevel == AndroidApiLevel.B;
+ if (minApiLevel == AndroidApiLevel.L) {
+ return true;
+ }
+ assert minApiLevel == AndroidApiLevel.B;
+ return !parallelMethods.contains(method.method);
+ });
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length != 2) {
+ System.out.println("Usage: GenerateLineFiles <desuage configuration> <output directory>");
+ System.exit(1);
+ }
+ new GenerateLintFiles(args[0], args[1]).run();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index ac75baa..9ccabb9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -218,6 +218,7 @@
public final DexString serviceLoaderDescriptor = createString("Ljava/util/ServiceLoader;");
public final DexString listDescriptor = createString("Ljava/util/List;");
public final DexString setDescriptor = createString("Ljava/util/Set;");
+ public final DexString collectionDescriptor = createString("Ljava/util/Collection;");
public final DexString comparatorDescriptor = createString("Ljava/util/Comparator;");
public final DexString callableDescriptor = createString("Ljava/util/concurrent/Callable;");
public final DexString supplierDescriptor = createString("Ljava/util/function/Supplier;");
@@ -307,6 +308,7 @@
public final DexType serviceLoaderType = createType(serviceLoaderDescriptor);
public final DexType listType = createType(listDescriptor);
public final DexType setType = createType(setDescriptor);
+ public final DexType collectionType = createType(collectionDescriptor);
public final DexType comparatorType = createType(comparatorDescriptor);
public final DexType callableType = createType(callableDescriptor);
public final DexType supplierType = createType(supplierDescriptor);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index d3dc54d..e1f2181 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
@@ -22,6 +23,7 @@
public class DesugaredLibraryConfiguration {
// TODO(b/134732760): should use DexString, DexType, DexMethod or so on when possible.
+ private final AndroidApiLevel requiredCompilationAPILevel;
private final boolean libraryCompilation;
private final Map<String, String> rewritePrefix;
private final Map<DexType, DexType> emulateLibraryInterface;
@@ -36,6 +38,7 @@
public static DesugaredLibraryConfiguration empty() {
return new DesugaredLibraryConfiguration(
+ AndroidApiLevel.B,
false,
ImmutableMap.of(),
ImmutableMap.of(),
@@ -46,6 +49,7 @@
}
public DesugaredLibraryConfiguration(
+ AndroidApiLevel requiredCompilationAPILevel,
boolean libraryCompilation,
Map<String, String> rewritePrefix,
Map<DexType, DexType> emulateLibraryInterface,
@@ -53,6 +57,7 @@
Map<DexType, DexType> backportCoreLibraryMember,
Map<DexType, DexType> customConversions,
List<Pair<DexType, DexString>> dontRewriteInvocation) {
+ this.requiredCompilationAPILevel = requiredCompilationAPILevel;
this.libraryCompilation = libraryCompilation;
this.rewritePrefix = rewritePrefix;
this.emulateLibraryInterface = emulateLibraryInterface;
@@ -68,6 +73,10 @@
: new DesugarPrefixRewritingMapper(rewritePrefix, factory);
}
+ public AndroidApiLevel getRequiredCompilationApiLevel() {
+ return requiredCompilationAPILevel;
+ }
+
public boolean isLibraryCompilation() {
return libraryCompilation;
}
@@ -100,6 +109,7 @@
private final DexItemFactory factory;
+ private AndroidApiLevel requiredCompilationAPILevel;
private boolean libraryCompilation = false;
private Map<String, String> rewritePrefix = new HashMap<>();
private Map<DexType, DexType> emulateLibraryInterface = new HashMap<>();
@@ -112,6 +122,11 @@
this.factory = dexItemFactory;
}
+ public Builder setRequiredCompilationAPILevel(AndroidApiLevel requiredCompilationAPILevel) {
+ this.requiredCompilationAPILevel = requiredCompilationAPILevel;
+ return this;
+ }
+
public Builder setProgramCompilation() {
libraryCompilation = false;
return this;
@@ -185,6 +200,7 @@
public DesugaredLibraryConfiguration build() {
return new DesugaredLibraryConfiguration(
+ requiredCompilationAPILevel,
libraryCompilation,
ImmutableMap.copyOf(rewritePrefix),
ImmutableMap.copyOf(emulateLibraryInterface),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
index 94467de..fbf3d1f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.StringResource;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.gson.JsonArray;
@@ -57,6 +58,10 @@
"Unsupported desugared library configuration version, please upgrade the D8/R8"
+ " compiler."));
}
+ int required_compilation_api_level =
+ jsonConfig.get("required_compilation_api_level").getAsInt();
+ configurationBuilder.setRequiredCompilationAPILevel(
+ AndroidApiLevel.getAndroidApiLevel(required_compilation_api_level));
JsonArray jsonFlags =
libraryCompilation
? jsonConfig.getAsJsonArray("library_flags")
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java
index de16ed5..843551e 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.jasmin.JasminBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
@@ -39,6 +40,7 @@
options ->
options.desugaredLibraryConfiguration =
new DesugaredLibraryConfiguration(
+ AndroidApiLevel.B,
false,
x,
ImmutableMap.of(),
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/LintFilesTest.java
new file mode 100644
index 0000000..87a6140
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/LintFilesTest.java
@@ -0,0 +1,94 @@
+// 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.corelib;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.GenerateLintFiles;
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class LintFilesTest extends TestBase {
+
+ private void checkFileContent(AndroidApiLevel minApiLevel, Path lintFile) throws Exception {
+ // Just do some light probing in the generated lint files.
+ List<String> methods = FileUtils.readAllLines(lintFile);
+ assertTrue(methods.contains("java/util/List/spliterator()Ljava/util/Spliterator;"));
+ assertTrue(methods.contains("java/util/Optional/empty()Ljava/util/Optional;"));
+ assertTrue(methods.contains("java/util/OptionalInt/empty()Ljava/util/OptionalInt;"));
+ assertEquals(
+ minApiLevel == AndroidApiLevel.L,
+ methods.contains("java/util/Collection/parallelStream()Ljava/util/stream/Stream;"));
+ assertEquals(
+ minApiLevel == AndroidApiLevel.L,
+ methods.contains(
+ "java/util/stream/DoubleStream/parallel()Ljava/util/stream/DoubleStream;"));
+ assertEquals(
+ minApiLevel == AndroidApiLevel.L,
+ methods.contains("java/util/stream/IntStream/parallel()Ljava/util/stream/IntStream;"));
+ }
+
+ @Test
+ public void testFileContent() throws Exception {
+ // Test require r8.jar not r8lib.jar, as the class com.android.tools.r8.GenerateLintFiles in
+ // not kept.
+ Assume.assumeTrue(!ToolHelper.isTestingR8Lib());
+
+ Path directory = temp.newFolder().toPath();
+ GenerateLintFiles.main(
+ new String[] {ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(), directory.toString()});
+ InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
+ DesugaredLibraryConfiguration desugaredLibraryConfiguration =
+ new DesugaredLibraryConfigurationParser(
+ options.itemFactory, options.reporter, false, AndroidApiLevel.B.getLevel())
+ .parse(StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+
+ for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
+ if (apiLevel == AndroidApiLevel.R) {
+ // Skip API level 30 for now.
+ continue;
+ }
+
+ if (apiLevel.getLevel()
+ >= desugaredLibraryConfiguration.getRequiredCompilationApiLevel().getLevel()) {
+ Path compileApiLevelDirectory =
+ directory.resolve("compile_api_level_" + apiLevel.getLevel());
+ assertTrue(Files.exists(compileApiLevelDirectory));
+ for (AndroidApiLevel minApiLevel : AndroidApiLevel.values()) {
+ String desugaredApisBaseName =
+ "desugared_apis_" + apiLevel.getLevel() + "_" + minApiLevel.getLevel();
+ if (minApiLevel == AndroidApiLevel.L || minApiLevel == AndroidApiLevel.B) {
+ assertTrue(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt")));
+ assertTrue(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".jar")));
+ checkFileContent(
+ minApiLevel, compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt"));
+ } else {
+ assertFalse(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".txt")));
+ assertFalse(
+ Files.exists(compileApiLevelDirectory.resolve(desugaredApisBaseName + ".jar")));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
index a08b6ce..3353fd2 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -79,6 +80,7 @@
options ->
options.desugaredLibraryConfiguration =
new DesugaredLibraryConfiguration(
+ AndroidApiLevel.B,
false,
ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
ImmutableMap.of(),
diff --git a/tools/create_maven_release.py b/tools/create_maven_release.py
index b4343f3..30c14c8 100755
--- a/tools/create_maven_release.py
+++ b/tools/create_maven_release.py
@@ -6,6 +6,7 @@
import argparse
import gradle
import hashlib
+import jdk
import json
from os import makedirs
from os.path import join
@@ -338,6 +339,19 @@
configuration_dir = join(tmp_dir, 'META-INF', 'desugar', 'd8')
makedirs(configuration_dir)
copyfile(configuration, join(configuration_dir, 'desugar.json'))
+
+ lint_dir = join(configuration_dir, 'lint')
+ makedirs(lint_dir)
+ cmd = [
+ jdk.GetJavaExecutable(),
+ '-cp',
+ utils.R8_JAR,
+ 'com.android.tools.r8.GenerateLintFiles',
+ configuration,
+ lint_dir]
+ utils.PrintCmd(cmd)
+ subprocess.check_call(cmd)
+
make_archive(destination, 'zip', tmp_dir)
move(destination + '.zip', destination)