Check desugared library implementation when generating lint files
Bug: 171971176
Change-Id: Idaf4b089fb2bfcf0b091693455a4ad37b716a5ec
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index b77db45..44a8d6e 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser;
import com.android.tools.r8.jar.CfApplicationWriter;
@@ -44,7 +45,6 @@
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;
@@ -56,7 +56,6 @@
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;
@@ -69,15 +68,21 @@
private final InternalOptions options = new InternalOptions(factory, reporter);
private final DesugaredLibraryConfiguration desugaredLibraryConfiguration;
- private final String outputDirectory;
+ private final Path desugaredLibraryImplementation;
+ private final Path outputDirectory;
private final Set<DexMethod> parallelMethods = Sets.newIdentityHashSet();
- public GenerateLintFiles(String desugarConfigurationPath, String outputDirectory) {
+ public GenerateLintFiles(
+ String desugarConfigurationPath, String desugarImplementationPath, String outputDirectory)
+ throws Exception {
this.desugaredLibraryConfiguration =
readDesugaredLibraryConfiguration(desugarConfigurationPath);
- this.outputDirectory =
- outputDirectory.endsWith("/") ? outputDirectory : outputDirectory + File.separator;
+ this.desugaredLibraryImplementation = Paths.get(desugarImplementationPath);
+ this.outputDirectory = Paths.get(outputDirectory);
+ if (!Files.isDirectory(this.outputDirectory)) {
+ throw new Exception("Output directory " + outputDirectory + " is not a directory");
+ }
DexType streamType = factory.createType(factory.createString("Ljava/util/stream/Stream;"));
DexMethod parallelMethod =
@@ -201,15 +206,18 @@
}
private SupportedMethods collectSupportedMethods(
- AndroidApiLevel compilationApiLevel, Predicate<DexEncodedMethod> supported)
- throws IOException, ExecutionException {
+ AndroidApiLevel compilationApiLevel, Predicate<DexEncodedMethod> supported) throws Exception {
- // Read the android.jar for the compilation API level.
AndroidApp library =
AndroidApp.builder().addLibraryFiles(getAndroidJarPath(compilationApiLevel)).build();
DirectMappedDexApplication dexApplication =
new ApplicationReader(library, options, Timing.empty()).read().toDirect();
+ AndroidApp implementation =
+ AndroidApp.builder().addProgramFiles(desugaredLibraryImplementation).build();
+ DirectMappedDexApplication implementationApplication =
+ new ApplicationReader(implementation, options, Timing.empty()).read().toDirect();
+
// Collect all the methods that the library desugar configuration adds support for.
Set<DexClass> classesWithAllMethodsSupported = Sets.newIdentityHashSet();
Map<DexClass, List<DexEncodedMethod>> supportedMethods = new LinkedHashMap<>();
@@ -218,9 +226,20 @@
// All the methods with the rewritten prefix are supported.
for (String prefix : desugaredLibraryConfiguration.getRewritePrefix().keySet()) {
if (clazz.accessFlags.isPublic() && className.startsWith(prefix)) {
+ DexProgramClass implementationClass =
+ implementationApplication.programDefinitionFor(clazz.getType());
+ if (implementationClass == null) {
+ throw new Exception("Implementation class not found for " + clazz.toSourceString());
+ }
boolean allMethodsAddad = true;
for (DexEncodedMethod method : clazz.methods()) {
- if (supported.test(method)) {
+ if (!method.isPublic()) {
+ continue;
+ }
+ ProgramMethod implementationMethod =
+ implementationClass.lookupProgramMethod(method.method);
+ // Don't include methods which are not implemented by the desugared library.
+ if (supported.test(method) && implementationMethod != null) {
supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
} else {
allMethodsAddad = false;
@@ -274,8 +293,7 @@
private Path lintFile(
AndroidApiLevel compilationApiLevel, AndroidApiLevel minApiLevel, String extension)
throws Exception {
- Path directory =
- Paths.get(outputDirectory + "compile_api_level_" + compilationApiLevel.getLevel());
+ Path directory = outputDirectory.resolve("compile_api_level_" + compilationApiLevel.getLevel());
Files.createDirectories(directory);
return Paths.get(
directory
@@ -299,6 +317,10 @@
DescriptorUtils.getClassBinaryNameFromDescriptor(clazz.type.descriptor.toString());
if (!supportedMethods.classesWithAllMethodsSupported.contains(clazz)) {
for (DexEncodedMethod method : methods) {
+ if (method.isInstanceInitializer() || method.isClassInitializer()) {
+ // No new constructors are added.
+ continue;
+ }
desugaredApisSignatures.add(
classBinaryName
+ '#'
@@ -379,10 +401,12 @@
}
public static void main(String[] args) throws Exception {
- if (args.length != 2) {
- System.out.println("Usage: GenerateLineFiles <desuage configuration> <output directory>");
+ if (args.length != 3) {
+ System.out.println(
+ "Usage: GenerateLineFiles <desugar configuration> <desugar implementation> <output"
+ + " directory>");
System.exit(1);
}
- new GenerateLintFiles(args[0], args[1]).run();
+ new GenerateLintFiles(args[0], args[1], args[2]).run();
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index 2225ceb..d5e8946 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -271,7 +271,10 @@
private CodeInspector getDesugaredApiJar() throws Exception {
Path out = temp.newFolder().toPath();
GenerateLintFiles desugaredApi =
- new GenerateLintFiles(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(), out.toString());
+ new GenerateLintFiles(
+ ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+ ToolHelper.DESUGAR_JDK_LIBS,
+ out.toString());
desugaredApi.run(targetApi.getLevel());
return new CodeInspector(
out.resolve("compile_api_level_" + targetApi.getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index b726614..43f53ab 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -37,6 +37,9 @@
assertTrue(methods.contains("java/util/Optional"));
assertTrue(methods.contains("java/util/OptionalInt"));
+ // ConcurrentHashMap is not fully supported.
+ assertFalse(methods.contains("java/util/concurrent/ConcurrentHashMap"));
+
// No parallel* methods pre L, and all stream methods supported from L.
assertEquals(
minApiLevel == AndroidApiLevel.L,
@@ -62,6 +65,22 @@
methods.contains(
"java/util/stream/IntStream#allMatch(Ljava/util/function/IntPredicate;)Z"));
+ // Supported methods on ConcurrentHashMap.
+ assertTrue(
+ methods.contains(
+ "java/util/concurrent/ConcurrentHashMap#getOrDefault(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"));
+
+ // Don't include constructors.
+ assertFalse(methods.contains("java/util/concurrent/ConcurrentHashMap#<init>()V"));
+
+ // Unsupported methods on ConcurrentHashMap.
+ assertFalse(
+ methods.contains(
+ "java/util/concurrent/ConcurrentHashMap#reduce(JLjava/util/function/BiFunction;Ljava/util/function/BiFunction;)Ljava/lang/Object;"));
+ assertFalse(
+ methods.contains(
+ "java/util/concurrent/ConcurrentHashMap#newKeySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;"));
+
// Emulated interface default method.
assertTrue(methods.contains("java/util/List#spliterator()Ljava/util/Spliterator;"));
@@ -85,7 +104,11 @@
Path directory = temp.newFolder().toPath();
GenerateLintFiles.main(
- new String[] {ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(), directory.toString()});
+ new String[] {
+ ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+ ToolHelper.DESUGAR_JDK_LIBS,
+ directory.toString()
+ });
InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
DesugaredLibraryConfiguration desugaredLibraryConfiguration =
new DesugaredLibraryConfigurationParser(
diff --git a/tools/utils.py b/tools/utils.py
index 3aad6c4..96708d2 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -56,6 +56,8 @@
DESUGAR_CONFIGURATION = os.path.join(
'src', 'library_desugar', 'desugar_jdk_libs.json')
+DESUGAR_IMPLEMENTATION = os.path.join(
+ 'third_party', 'openjdk', 'desugar_jdk_libs', 'libjava.jar')
DESUGAR_CONFIGURATION_MAVEN_ZIP = os.path.join(
LIBS, 'desugar_jdk_libs_configuration.zip')
GENERATED_LICENSE = os.path.join(GENERATED_LICENSE_DIR, 'LICENSE')