Let ArchiveClassFileProvider allow subclasses

This will allow the Gradle plugin to make a caching version and also
allow it to make explicit close of those.

Bug: 62051319
Change-Id: I49283bf765046cc1ac80601e36545149bc7bc450
diff --git a/build.gradle b/build.gradle
index 9539df2..a678d76 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1462,8 +1462,10 @@
 task javadocD8(type: Javadoc) {
   classpath = sourceSets.main.compileClasspath
   source = sourceSets.main.allJava
+  include '**/com/android/tools/r8/ArchiveClassFileProvider.java'
   include '**/com/android/tools/r8/BaseCommand.java'
   include '**/com/android/tools/r8/BaseOutput.java'
+  include '**/com/android/tools/r8/ClassFileResourceProvider.java'
   include '**/com/android/tools/r8/CompilationException.java'
   include '**/com/android/tools/r8/CompilationMode.java'
   include '**/com/android/tools/r8/D8.java'
diff --git a/src/main/java/com/android/tools/r8/utils/ArchiveClassFileProvider.java b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
similarity index 71%
rename from src/main/java/com/android/tools/r8/utils/ArchiveClassFileProvider.java
rename to src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
index 2828610..0313cf8 100644
--- a/src/main/java/com/android/tools/r8/utils/ArchiveClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
@@ -1,18 +1,17 @@
 // Copyright (c) 2017, 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.utils;
+package com.android.tools.r8;
 
 import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.isArchive;
 import static com.android.tools.r8.utils.FileUtils.isClassFile;
 
-import com.android.tools.r8.ClassFileResourceProvider;
-import com.android.tools.r8.Resource;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.shaking.FilteredClassPath;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.io.ByteStreams;
-import java.io.File;
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Path;
@@ -27,7 +26,7 @@
 /**
  * Lazy Java class file resource provider loading class files form a zip archive.
  */
-public final class ArchiveClassFileProvider implements ClassFileResourceProvider {
+public class ArchiveClassFileProvider implements ClassFileResourceProvider, Closeable {
 
   private final Set<String> descriptors = new HashSet<>();
   private final ZipFile zipFile;
@@ -37,24 +36,8 @@
     return new ArchiveClassFileProvider(archive);
   }
 
-  // Guess class descriptor from location of the class file.
-  static String guessTypeDescriptor(Path name) {
-    return guessTypeDescriptor(name.toString());
-  }
-
-  // Guess class descriptor from location of the class file.
-  private static String guessTypeDescriptor(String name) {
-    assert name != null;
-    assert name.endsWith(CLASS_EXTENSION) :
-        "Name " + name + " must have " + CLASS_EXTENSION + " suffix";
-    String fileName =
-        File.separatorChar == '/' ? name.toString() :
-            name.toString().replace(File.separatorChar, '/');
-    String descriptor = fileName.substring(0, fileName.length() - CLASS_EXTENSION.length());
-    if (descriptor.contains(".")) {
-      throw new CompilationError("Unexpected file name in the archive: " + fileName);
-    }
-    return 'L' + descriptor + ';';
+  protected ArchiveClassFileProvider(Path archive) throws IOException {
+    this(FilteredClassPath.unfiltered(archive));
   }
 
   private ArchiveClassFileProvider(FilteredClassPath archive) throws IOException {
@@ -66,7 +49,7 @@
       String name = entry.getName();
       Path entryPath = Paths.get(name);
       if (isClassFile(entryPath) && archive.matchesFile(entryPath)) {
-        descriptors.add(guessTypeDescriptor(name));
+        descriptors.add(DescriptorUtils.guessTypeDescriptor(name));
       }
     }
   }
@@ -95,7 +78,7 @@
 
   @Override
   protected void finalize() throws Throwable {
-    zipFile.close();
+    close();
     super.finalize();
   }
 
@@ -104,6 +87,11 @@
     return descriptors.size() + " resources from '" + zipFile.getName() +"'";
   }
 
+  @Override
+  public void close() throws IOException {
+    zipFile.close();
+  }
+
   private ZipEntry getZipEntryFromDescriptor(String descriptor) {
     return zipFile.getEntry(descriptor.substring(1, descriptor.length() - 1) + CLASS_EXTENSION);
   }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 6064b64..80a2393 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -8,6 +8,7 @@
 import static com.android.tools.r8.utils.FileUtils.isDexFile;
 import static com.android.tools.r8.utils.FileUtils.isVDexFile;
 
+import com.android.tools.r8.ArchiveClassFileProvider;
 import com.android.tools.r8.ClassFileResourceProvider;
 import com.android.tools.r8.Resource;
 import com.android.tools.r8.Resource.Kind;
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index 84beae5..ee3c845 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -4,9 +4,14 @@
 
 package com.android.tools.r8.utils;
 
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.nio.file.Path;
 import java.util.Map;
 
 public class DescriptorUtils {
@@ -249,4 +254,23 @@
     }
   }
 
+  // Guess class descriptor from location of the class file.
+  public static String guessTypeDescriptor(Path name) {
+    return guessTypeDescriptor(name.toString());
+  }
+
+  // Guess class descriptor from location of the class file.
+  public static String guessTypeDescriptor(String name) {
+    assert name != null;
+    assert name.endsWith(CLASS_EXTENSION) :
+        "Name " + name + " must have " + CLASS_EXTENSION + " suffix";
+    String fileName =
+        File.separatorChar == '/' ? name.toString() :
+            name.toString().replace(File.separatorChar, '/');
+    String descriptor = fileName.substring(0, fileName.length() - CLASS_EXTENSION.length());
+    if (descriptor.contains(".")) {
+      throw new CompilationError("Unexpected class file name: " + fileName);
+    }
+    return 'L' + descriptor + ';';
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java b/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
index fa6d5fb..f33bf77 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
@@ -55,7 +55,7 @@
                 dexResources.add(resource);
               }
             } else if (isClassFile(name)) {
-              String descriptor = ArchiveClassFileProvider.guessTypeDescriptor(name);
+              String descriptor = DescriptorUtils.guessTypeDescriptor(name);
               Resource resource = new OneShotByteResource(Resource.Kind.CLASSFILE,
                   ByteStreams.toByteArray(stream), Collections.singleton(descriptor));
               classResources.add(resource);
diff --git a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
index 7de4f7f..45939db 100644
--- a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
@@ -11,11 +11,9 @@
 import com.android.tools.r8.shaking.FilteredClassPath;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.ArchiveClassFileProvider;
 import com.android.tools.r8.utils.DirectoryClassFileProvider;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.OffOrAuto;
-import com.android.tools.r8.utils.PreloadedClassFileProvider;
 import com.android.tools.r8.utils.ZipUtils;
 import java.io.IOException;
 import java.nio.file.Files;