Desugared lib: Fix DirectoryStream apis
Change-Id: Ie7bec1f6d0f8d0286207038ea572e855a6d8a8fb
diff --git a/src/library_desugar/java/j$/nio/file/Path.java b/src/library_desugar/java/j$/nio/file/Path.java
index 781ab5f..6030764 100644
--- a/src/library_desugar/java/j$/nio/file/Path.java
+++ b/src/library_desugar/java/j$/nio/file/Path.java
@@ -9,4 +9,8 @@
public static j$.nio.file.Path wrap_convert(java.nio.file.Path path) {
return null;
}
+
+ public static java.nio.file.Path wrap_convert(j$.nio.file.Path path) {
+ return null;
+ }
}
diff --git a/src/library_desugar/java/java/nio/file/PathApiFlips.java b/src/library_desugar/java/java/nio/file/PathApiFlips.java
new file mode 100644
index 0000000..7314b7f
--- /dev/null
+++ b/src/library_desugar/java/java/nio/file/PathApiFlips.java
@@ -0,0 +1,137 @@
+// Copyright (c) 2022, 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 java.nio.file;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.function.Consumer;
+
+/** For all wrappers, the spliterator is based on the iterator so no need to wrap it. */
+public class PathApiFlips {
+
+ public static Iterator<?> flipIteratorPath(Iterator<?> iterator) {
+ return new IteratorPathWrapper<>(iterator);
+ }
+
+ public static Iterable<?> flipIterablePath(Iterable<?> iterable) {
+ return new IterablePathWrapper<>(iterable);
+ }
+
+ public static java.nio.file.DirectoryStream<?> flipDirectoryStreamPath(
+ java.nio.file.DirectoryStream<?> directoryStream) {
+ return new DirectoryStreamPathWrapper<>(directoryStream);
+ }
+
+ public static java.nio.file.DirectoryStream.Filter<?> flipDirectoryStreamFilterPath(
+ java.nio.file.DirectoryStream.Filter<?> filter) {
+ return new DirectoryStreamFilterWrapper<>(filter);
+ }
+
+ /**
+ * The generic types inherit from java.lang.Object even if in practice it seems they are
+ * exclusively used with Path. To be conservative, we return the parameter if it's not a path so
+ * the code works for non Path objects.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T convertPath(T maybePath) {
+ if (maybePath == null) {
+ return null;
+ }
+ if (maybePath instanceof java.nio.file.Path) {
+ return (T) j$.nio.file.Path.wrap_convert((java.nio.file.Path) maybePath);
+ }
+ if (maybePath instanceof j$.nio.file.Path) {
+ return (T) j$.nio.file.Path.wrap_convert((j$.nio.file.Path) maybePath);
+ }
+ return maybePath;
+ }
+
+ public static class DirectoryStreamFilterWrapper<T>
+ implements java.nio.file.DirectoryStream.Filter<T> {
+
+ private final java.nio.file.DirectoryStream.Filter<T> filter;
+
+ public DirectoryStreamFilterWrapper(java.nio.file.DirectoryStream.Filter<T> filter) {
+ this.filter = filter;
+ }
+
+ @Override
+ public boolean accept(T t) throws IOException {
+ return filter.accept(convertPath(t));
+ }
+ }
+
+ public static class IterablePathWrapper<T> implements Iterable<T> {
+
+ private final Iterable<T> iterable;
+
+ public IterablePathWrapper(Iterable<T> iterable) {
+ this.iterable = iterable;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new IteratorPathWrapper<>(iterable.iterator());
+ }
+
+ @Override
+ public void forEach(Consumer<? super T> action) {
+ iterable.forEach(path -> action.accept(convertPath(path)));
+ }
+ }
+
+ public static class IteratorPathWrapper<T> implements Iterator<T> {
+
+ private final Iterator<T> iterator;
+
+ public IteratorPathWrapper(Iterator<T> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ return convertPath(iterator.next());
+ }
+
+ @Override
+ public void remove() {
+ iterator.remove();
+ }
+
+ @Override
+ public void forEachRemaining(Consumer<? super T> action) {
+ iterator.forEachRemaining(path -> action.accept(convertPath(path)));
+ }
+ }
+
+ public static class DirectoryStreamPathWrapper<T> implements DirectoryStream<T> {
+
+ private final DirectoryStream<T> directoryStream;
+
+ public DirectoryStreamPathWrapper(DirectoryStream<T> directoryStream) {
+ this.directoryStream = directoryStream;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new IteratorPathWrapper<>(directoryStream.iterator());
+ }
+
+ @Override
+ public void forEach(Consumer<? super T> action) {
+ directoryStream.forEach(path -> action.accept(convertPath(path)));
+ }
+
+ @Override
+ public void close() throws IOException {
+ directoryStream.close();
+ }
+ }
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
index 9bc2704..090d1f2 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -152,6 +152,7 @@
"java.nio.file.ClosedWatchServiceException",
"java.nio.file.DirectoryIteratorException",
"java.nio.file.DirectoryNotEmptyException",
+ "java.nio.file.DirectoryStream",
"java.nio.file.FileAlreadyExistsException",
"java.nio.file.FileSystemAlreadyExistsException",
"java.nio.file.FileSystemException",
@@ -173,6 +174,7 @@
"java.nio.file.ClosedWatchServiceException",
"java.nio.file.DirectoryIteratorException",
"java.nio.file.DirectoryNotEmptyException",
+ "java.nio.file.DirectoryStream",
"java.nio.file.FileAlreadyExistsException",
"java.nio.file.FileSystemAlreadyExistsException",
"java.nio.file.FileSystemException",
@@ -199,7 +201,10 @@
"java.nio.file.attribute.BasicFileAttributes java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.Class, java.nio.file.LinkOption[])": [1, "java.lang.Class java.nio.file.FileApiFlips#flipFileAttributes(java.lang.Class)"],
"java.util.Set java.nio.file.attribute.PosixFileAttributes#permissions()": [-1, "java.util.Set java.nio.file.FileApiFlips#flipPosixPermissionSet(java.util.Set)"],
"void java.nio.file.attribute.PosixFileAttributeView#setPermissions(java.util.Set)": [0, "java.util.Set java.nio.file.FileApiFlips#flipPosixPermissionSet(java.util.Set)"],
- "java.util.Map java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption[])" : [-1, "java.util.Map java.nio.file.FileApiFlips#flipMapWithMaybeFileTimeValues(java.util.Map)"]
+ "java.util.Map java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption[])" : [-1, "java.util.Map java.nio.file.FileApiFlips#flipMapWithMaybeFileTimeValues(java.util.Map)"],
+ "java.lang.Iterable java.nio.file.FileSystem#getRootDirectories()": [-1, "java.lang.Iterable java.nio.file.PathApiFlips#flipIterablePath(java.lang.Iterable)"],
+ "java.util.Iterator java.nio.file.Path#iterator()": [-1, "java.util.Iterator java.nio.file.PathApiFlips#flipIteratorPath(java.util.Iterator)"],
+ "java.nio.file.DirectoryStream java.nio.file.spi.FileSystemProvider#newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream$Filter)": [-1, "java.nio.file.DirectoryStream java.nio.file.PathApiFlips#flipDirectoryStreamPath(java.nio.file.DirectoryStream)", 1, "java.nio.file.DirectoryStream$Filter java.nio.file.PathApiFlips#flipDirectoryStreamFilterPath(java.nio.file.DirectoryStream$Filter)"]
},
"wrapper_conversion": [
"java.nio.channels.CompletionHandler",
@@ -225,8 +230,6 @@
"java.nio.file.attribute.UserPrincipal",
"java.nio.file.FileStore",
"java.nio.file.attribute.FileStoreAttributeView",
- "java.nio.file.DirectoryStream$Filter",
- "java.nio.file.DirectoryStream",
"java.nio.file.attribute.PosixFilePermission",
"java.nio.file.attribute.BasicFileAttributes",
"java.nio.file.attribute.PosixFileAttributes",
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 b5ca98b..a68f3ce 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
@@ -123,13 +123,7 @@
// TODO(b/238179854): Investigate how to fix these.
private static final Set<String> MISSING_GENERIC_TYPE_CONVERSION_PATH =
- ImmutableSet.of(
- "java.lang.Iterable java.nio.file.FileSystem.getFileStores()",
- "java.lang.Iterable java.nio.file.FileSystem.getRootDirectories()",
- "java.util.Iterator java.nio.file.Path.iterator()",
- "java.nio.file.DirectoryStream"
- + " java.nio.file.spi.FileSystemProvider.newDirectoryStream(java.nio.file.Path,"
- + " java.nio.file.DirectoryStream$Filter)");
+ ImmutableSet.of("java.lang.Iterable java.nio.file.FileSystem.getFileStores()");
// TODO(b/238179854): Investigate how to fix these.
private static final Set<String> MISSING_GENERIC_TYPE_CONVERSION_FLOW =
@@ -245,6 +239,18 @@
.collect(Collectors.toSet());
Set<String> maintainTypeInSet =
specification.getMaintainType().stream().map(DexType::toString).collect(Collectors.toSet());
+ Map<String, boolean[]> genericConversionsInSpec = new HashMap<>();
+ specification
+ .getApiGenericConversion()
+ .forEach(
+ (method, generics) -> {
+ boolean[] indexes = new boolean[generics.length];
+ for (int i = 0; i < generics.length; i++) {
+ indexes[i] = generics[i] != null;
+ }
+ genericConversionsInSpec.put(method.toString(), indexes);
+ });
+
assertEquals(
Collections.emptySet(), Sets.intersection(wrappersInSpec, customConversionsInSpec));
@@ -257,6 +263,7 @@
nonDesugaredJar,
customConversionsInSpec,
maintainTypeInSet,
+ genericConversionsInSpec,
genericDependencies);
Map<ClassReference, Set<ClassReference>> indirectWrappers =
getIndirectlyReferencedWrapperTypes(
@@ -266,6 +273,7 @@
customConversionsInSpec,
maintainTypeInSet,
specification.getWrappers(),
+ genericConversionsInSpec,
genericDependencies);
{
Set<String> missingGenericDependency = new HashSet<>();
@@ -339,6 +347,7 @@
CodeInspector nonDesugaredJar,
Set<String> customConversions,
Set<String> maintainType,
+ Map<String, boolean[]> genericConversionsInSpec,
Set<DexEncodedMethod> genericDependencies) {
Map<ClassReference, Set<MethodReference>> directWrappers = new HashMap<>();
nonDesugaredJar.forAllClasses(
@@ -364,6 +373,7 @@
forEachType(
method,
t -> addType(adder, t, preDesugarTypes, customConversions, maintainType),
+ genericConversionsInSpec,
genericDependencies);
});
});
@@ -373,12 +383,20 @@
private void forEachType(
FoundMethodSubject subject,
Function<String, Boolean> process,
+ Map<String, boolean[]> genericConversionsInSpec,
Set<DexEncodedMethod> generics) {
+ boolean[] genericConversions = genericConversionsInSpec.get(subject.toString());
MethodSignature signature = subject.getFinalSignature().asMethodSignature();
- process.apply(signature.type);
- for (String parameter : signature.parameters) {
- process.apply(parameter);
+ if (genericConversions == null || !genericConversions[genericConversions.length - 1]) {
+ process.apply(signature.type);
}
+ for (int i = 0; i < signature.parameters.length; i++) {
+ if (genericConversions == null || !genericConversions[i]) {
+ process.apply(signature.parameters[i]);
+ }
+ }
+ // Even if the genericConversions are present, we check the generic types since conversions
+ // on such types will happen through the hand written custom wrappers.
MethodTypeSignature genericSignature = subject.getMethod().getGenericSignature();
if (genericSignature != null) {
TypeSignature[] typeSignatures = new TypeSignature[signature.parameters.length + 1];
@@ -387,15 +405,17 @@
}
typeSignatures[signature.parameters.length] = genericSignature.returnType().typeSignature();
for (TypeSignature typeSignature : typeSignatures) {
- if ((typeSignature instanceof ClassTypeSignature)) {
- for (FieldTypeSignature typeArgument :
- ((ClassTypeSignature) typeSignature).typeArguments()) {
- if (typeArgument instanceof ClassTypeSignature) {
- String type = descriptorToJavaType(typeArgument.toString()).split("<")[0];
- if (!GENERIC_NOT_NEEDED.contains(type)) {
- boolean added = process.apply(type);
- if (added) {
- generics.add(subject.getMethod());
+ if (typeSignature != null) {
+ if ((typeSignature instanceof ClassTypeSignature)) {
+ for (FieldTypeSignature typeArgument :
+ ((ClassTypeSignature) typeSignature).typeArguments()) {
+ if (typeArgument instanceof ClassTypeSignature) {
+ String type = descriptorToJavaType(typeArgument.toString()).split("<")[0];
+ if (!GENERIC_NOT_NEEDED.contains(type)) {
+ boolean added = process.apply(type);
+ if (added) {
+ generics.add(subject.getMethod());
+ }
}
}
}
@@ -412,6 +432,7 @@
Set<String> customConversions,
Set<String> maintainType,
Map<DexType, WrapperDescriptor> wrapperDescriptorMap,
+ Map<String, boolean[]> genericConversionsInSpec,
Set<DexEncodedMethod> genericDependencies) {
Map<ClassReference, Set<ClassReference>> indirectWrappers = new HashMap<>();
WorkList<ClassReference> worklist = WorkList.newEqualityWorkList(directWrappers.keySet());
@@ -435,6 +456,7 @@
forEachType(
method,
t -> addType(adder, t, existing, customConversions, maintainType),
+ genericConversionsInSpec,
genericDependencies);
});
WrapperDescriptor descriptor = wrapperDescriptorMap.get(clazz.getDexProgramClass().getType());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
index 9508e8c..cef3785 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
@@ -18,6 +18,7 @@
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
+import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
@@ -28,6 +29,7 @@
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -50,7 +52,10 @@
"null",
"true",
"unsupported",
- "j$.nio.file.attribute");
+ "j$.nio.file.attribute",
+ "tmp",
+ "/",
+ "true");
private static final String EXPECTED_RESULT_DESUGARING_FILE_SYSTEM_PLATFORM_CHANNEL =
StringUtils.lines(
"bytes written: 11",
@@ -62,7 +67,10 @@
"null",
"true",
"unsupported",
- "j$.nio.file.attribute");
+ "j$.nio.file.attribute",
+ "tmp",
+ "/",
+ "true");
private static final String EXPECTED_RESULT_PLATFORM_FILE_SYSTEM_DESUGARING =
StringUtils.lines(
"bytes written: 11",
@@ -74,7 +82,10 @@
"true",
"true",
"true",
- "j$.nio.file.attribute");
+ "j$.nio.file.attribute",
+ "tmp",
+ "/",
+ "true");
private static final String EXPECTED_RESULT_PLATFORM_FILE_SYSTEM =
StringUtils.lines(
"bytes written: 11",
@@ -86,7 +97,10 @@
"true",
"true",
"true",
- "java.nio.file.attribute");
+ "java.nio.file.attribute",
+ "tmp",
+ "/",
+ "true");
private final TestParameters parameters;
private final LibraryDesugaringSpecification libraryDesugaringSpecification;
@@ -144,6 +158,18 @@
readThroughFileChannelAPI(path);
attributeAccess(path);
fspMethodsWithGeneric(path);
+ pathGeneric();
+ }
+
+ private static void pathGeneric() throws IOException {
+ Path tmpDict = Files.createTempDirectory("tmpDict");
+ Path tmpFile = Files.createFile(tmpDict.resolve("tmpFile"));
+ Iterator<Path> iterator = tmpDict.iterator();
+ System.out.println(iterator.next());
+ Iterable<Path> rootDirectories = tmpFile.getFileSystem().getRootDirectories();
+ System.out.println(rootDirectories.iterator().next());
+ DirectoryStream<Path> paths = Files.newDirectoryStream(tmpDict);
+ System.out.println(paths.iterator().hasNext());
}
private static void fspMethodsWithGeneric(Path path) throws IOException {