diff options
author | 2015-02-18 18:20:15 +0000 | |
---|---|---|
committer | 2015-02-18 18:20:15 +0000 | |
commit | ca52a6ca2a4c1272eed161405897a57e53ad6b38 (patch) | |
tree | 52d52ce789998b4b14f0485b26b81cafd6541ab0 /src/java_tools | |
parent | d46060f124cd970632b07f539fe00489e57a2c60 (diff) |
Prepare strict deps for using JavacPathFileManager.
This lays the groundwork for using a JavacPathFileManager and Jimfs to test
strict deps and the dependency extractor, instead of the ad-hoc in-memory
filesystem implementation in InMemoryJavaFileManager. The current
implementation is deeply impressive, but scary to maintain and entirely
unnecessary now that we have nio-based filemangers Jimfs.
RELNOTES: N/A
--
MOS_MIGRATED_REVID=86606317
Diffstat (limited to 'src/java_tools')
2 files changed, 140 insertions, 81 deletions
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/ImplicitDependencyExtractor.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/ImplicitDependencyExtractor.java index df7190d787..6d7d99e580 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/ImplicitDependencyExtractor.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/ImplicitDependencyExtractor.java @@ -14,24 +14,27 @@ package com.google.devtools.build.buildjar.javac.plugins.dependency; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.view.proto.Deps; +import com.sun.nio.zipfs.ZipFileSystem; +import com.sun.nio.zipfs.ZipPath; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.file.ZipArchive; import com.sun.tools.javac.file.ZipFileIndexArchive; +import com.sun.tools.javac.nio.JavacPathFileManager; import com.sun.tools.javac.util.Context; -import java.io.IOError; -import java.io.IOException; -import java.util.EnumSet; -import java.util.HashSet; +import java.io.File; +import java.nio.file.Path; import java.util.Map; import java.util.Set; import javax.lang.model.util.SimpleTypeVisitor7; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; /** @@ -59,7 +62,7 @@ public class ImplicitDependencyExtractor { JavaFileManager fileManager) { this.depsSet = depsSet; this.depsMap = depsMap; - this.fileManager = fileManager; + this.fileManager = unwrapFileManager(fileManager); } /** @@ -85,40 +88,45 @@ public class ImplicitDependencyExtractor { root.type.accept(typeVisitor, null); } - Set<JavaFileObject> platformClasses = getPlatformClasses(fileManager); + Set<String> platformJars = getPlatformJars(fileManager); // Collect all other partially resolved types for (ClassSymbol cs : symtab.classes.values()) { if (cs.classfile != null) { - collectJarOf(cs.classfile, platformClasses); + collectJarOf(cs.classfile, platformJars); } else if (cs.sourcefile != null) { - collectJarOf(cs.sourcefile, platformClasses); + collectJarOf(cs.sourcefile, platformJars); } } } /** - * Collect the set of classes on the compilation bootclasspath. - * - * <p>TODO(bazel-team): this needs some work. JavaFileManager.list() is slower than - * StandardJavaFileManager.getLocation() and doesn't get cached. Additionally, tracking all - * classes in the bootclasspath requires a much bigger set than just tracking a list of jars. - * However, relying on the context containing a StandardJavaFileManager is brittle (e.g. Lombok - * wraps the file-manager in a ForwardingJavaFileManager.) + * Collect the set of jars on the compilation bootclasspath. */ - public static HashSet<JavaFileObject> getPlatformClasses(JavaFileManager fileManager) { - HashSet<JavaFileObject> result = new HashSet<JavaFileObject>(); - Iterable<JavaFileObject> files; - try { - files = fileManager.list( - StandardLocation.PLATFORM_CLASS_PATH, "", EnumSet.of(JavaFileObject.Kind.CLASS), true); - } catch (IOException e) { - throw new IOError(e); + public static Set<String> getPlatformJars(JavaFileManager fileManager) { + + if (fileManager instanceof StandardJavaFileManager) { + StandardJavaFileManager sjfm = (StandardJavaFileManager) fileManager; + ImmutableSet.Builder<String> result = ImmutableSet.builder(); + for (File jar : sjfm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) { + result.add(jar.toString()); + } + return result.build(); } - for (JavaFileObject file : files) { - result.add(file); + + if (fileManager instanceof JavacPathFileManager) { + JavacPathFileManager jpfm = (JavacPathFileManager) fileManager; + ImmutableSet.Builder<String> result = ImmutableSet.builder(); + for (Path jar : jpfm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) { + result.add(jar.toString()); + } + return result.build(); } - return result; + + // TODO(cushon): Assuming JavacPathFileManager or StandardJavaFileManager is slightly brittle, + // but in practice those are the only implementations that matter. + throw new IllegalStateException("Unsupported file manager type: " + + fileManager.getClass().toString()); } /** @@ -126,25 +134,50 @@ public class ImplicitDependencyExtractor { * to the collection, filtering out jars on the compilation bootclasspath. * * @param reference JavaFileObject representing a class or source file - * @param platformClasses classes on javac's bootclasspath + * @param platformJars classes on javac's bootclasspath */ - private void collectJarOf(JavaFileObject reference, Set<JavaFileObject> platformClasses) { - reference = unwrapFileObject(reference); - if (reference instanceof ZipArchive.ZipFileObject || - reference instanceof ZipFileIndexArchive.ZipFileIndexFileObject) { + private void collectJarOf(JavaFileObject reference, Set<String> platformJars) { + + String name = getJarName(fileManager, reference); + if (name == null) { + return; + } + + // Filter out classes in rt.jar + if (platformJars.contains(name)) { + return; + } + + depsSet.add(name); + if (!depsMap.containsKey(name)) { + depsMap.put(name, Deps.Dependency.newBuilder() + .setKind(Deps.Dependency.Kind.IMPLICIT) + .setPath(name) + .build()); + } + } + + public static String getJarName(JavaFileManager fileManager, JavaFileObject file) { + file = unwrapFileObject(file); + + if (file instanceof ZipArchive.ZipFileObject + || file instanceof ZipFileIndexArchive.ZipFileIndexFileObject) { // getName() will return something like com/foo/libfoo.jar(Bar.class) - String name = reference.getName().split("\\(")[0]; - // Filter out classes in rt.jar - if (!platformClasses.contains(reference)) { - depsSet.add(name); - if (!depsMap.containsKey(name)) { - depsMap.put(name, Deps.Dependency.newBuilder() - .setKind(Deps.Dependency.Kind.IMPLICIT) - .setPath(name) - .build()); - } + return file.getName().split("\\(")[0]; + } + + if (fileManager instanceof JavacPathFileManager) { + JavacPathFileManager fm = (JavacPathFileManager) fileManager; + Path path = fm.getPath(file); + if (!(path instanceof ZipPath)) { + return null; } + ZipFileSystem zipfs = ((ZipPath) path).getFileSystem(); + // calls toString() on the path to the zip archive + return zipfs.toString(); } + + return null; } @@ -152,19 +185,23 @@ public class ImplicitDependencyExtractor { // TODO(bazel-team): Override the visitor methods we're interested in. } - private static final Class<?> WRAPPED_JAVA_FILE_OBJECT = - getClassOrDie("com.sun.tools.javac.api.ClientCodeWrapper$WrappedJavaFileObject"); + private static final Class<?> WRAPPED_FILE_OBJECT = + getClassOrDie("com.sun.tools.javac.api.ClientCodeWrapper$WrappedFileObject"); - private static final java.lang.reflect.Field UNWRAP_FIELD = - getFieldOrDie( - getClassOrDie("com.sun.tools.javac.api.ClientCodeWrapper$WrappedFileObject"), - "clientFileObject"); + private static final java.lang.reflect.Field UNWRAP_FILE_FIELD = + getFieldOrDie(WRAPPED_FILE_OBJECT, "clientFileObject"); + + private static final Class<?> WRAPPED_JAVA_FILE_MANAGER = + getClassOrDie("com.sun.tools.javac.api.ClientCodeWrapper$WrappedJavaFileManager"); + + private static final java.lang.reflect.Field UNWRAP_FILE_MANAGER_FIELD = + getFieldOrDie(WRAPPED_JAVA_FILE_MANAGER, "clientJavaFileManager"); private static Class<?> getClassOrDie(String name) { try { return Class.forName(name); - } catch (ClassNotFoundException e) { - throw new LinkageError(e.getMessage()); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); } } @@ -174,16 +211,27 @@ public class ImplicitDependencyExtractor { field.setAccessible(true); return field; } catch (ReflectiveOperationException e) { - throw new LinkageError(e.getMessage()); + throw new LinkageError(e.getMessage(), e); } } public static JavaFileObject unwrapFileObject(JavaFileObject file) { - if (!file.getClass().equals(WRAPPED_JAVA_FILE_OBJECT)) { + if (!WRAPPED_FILE_OBJECT.isInstance(file)) { return file; } try { - return (JavaFileObject) UNWRAP_FIELD.get(file); + return (JavaFileObject) UNWRAP_FILE_FIELD.get(file); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage()); + } + } + + public static JavaFileManager unwrapFileManager(JavaFileManager fileManager) { + if (!WRAPPED_JAVA_FILE_MANAGER.isInstance(fileManager)) { + return fileManager; + } + try { + return (JavaFileManager) UNWRAP_FILE_MANAGER_FIELD.get(fileManager); } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage()); } diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/StrictJavaDepsPlugin.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/StrictJavaDepsPlugin.java index 6ad6d58c7c..35eaf9c2f6 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/StrictJavaDepsPlugin.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/StrictJavaDepsPlugin.java @@ -15,7 +15,8 @@ package com.google.devtools.build.buildjar.javac.plugins.dependency; import static com.google.devtools.build.buildjar.javac.plugins.dependency.DependencyModule.StrictJavaDeps.ERROR; -import static com.google.devtools.build.buildjar.javac.plugins.dependency.ImplicitDependencyExtractor.getPlatformClasses; +import static com.google.devtools.build.buildjar.javac.plugins.dependency.ImplicitDependencyExtractor.getPlatformJars; +import static com.google.devtools.build.buildjar.javac.plugins.dependency.ImplicitDependencyExtractor.unwrapFileManager; import static com.google.devtools.build.buildjar.javac.plugins.dependency.ImplicitDependencyExtractor.unwrapFileObject; import com.google.common.annotations.VisibleForTesting; @@ -30,8 +31,6 @@ import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; -import com.sun.tools.javac.file.ZipArchive; -import com.sun.tools.javac.file.ZipFileIndexArchive; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeScanner; @@ -86,6 +85,8 @@ public final class StrictJavaDepsPlugin extends BlazeJavaCompilerPlugin { private static Properties targetMap; + private JavaFileManager fileManager; + private PrintWriter errWriter; /** @@ -112,15 +113,15 @@ public final class StrictJavaDepsPlugin extends BlazeJavaCompilerPlugin { public void init(Context context, Log log, JavaCompiler compiler) { super.init(context, log, compiler); errWriter = log.getWriter(WriterKind.ERROR); - JavaFileManager fileManager = context.get(JavaFileManager.class); + this.fileManager = unwrapFileManager(context.get(JavaFileManager.class)); implicitDependencyExtractor = new ImplicitDependencyExtractor( dependencyModule.getUsedClasspath(), dependencyModule.getImplicitDependenciesMap(), fileManager); checkingTreeScanner = context.get(CheckingTreeScanner.class); if (checkingTreeScanner == null) { - Set<JavaFileObject> platformClasses = getPlatformClasses(fileManager); + Set<String> platformJars = getPlatformJars(fileManager); checkingTreeScanner = new CheckingTreeScanner( - dependencyModule, log, missingTargets, platformClasses); + dependencyModule, log, missingTargets, platformJars, fileManager); context.put(CheckingTreeScanner.class, checkingTreeScanner); } initTargetMap(); @@ -196,6 +197,9 @@ public final class StrictJavaDepsPlugin extends BlazeJavaCompilerPlugin { /** All error reporting is done through javac's log, */ private final Log log; + /** The compilation's file manager. */ + private final JavaFileManager fileManager; + /** The strict_java_deps mode */ private final StrictJavaDeps strictJavaDepsMode; @@ -209,17 +213,18 @@ public final class StrictJavaDepsPlugin extends BlazeJavaCompilerPlugin { private final Set<ClassSymbol> seenClasses = new HashSet<>(); private final Set<String> seenTargets = new HashSet<>(); - /** The set of classes on the compilation bootclasspath. */ - private final Set<JavaFileObject> platformClasses; + /** The set of jars on the compilation bootclasspath. */ + private final Set<String> platformJars; public CheckingTreeScanner(DependencyModule dependencyModule, Log log, - Set<String> missingTargets, Set<JavaFileObject> platformClasses) { + Set<String> missingTargets, Set<String> platformJars, JavaFileManager fileManager) { this.indirectJarsToTargets = dependencyModule.getIndirectMapping(); this.strictJavaDepsMode = dependencyModule.getStrictJavaDeps(); this.log = log; this.missingTargets = missingTargets; this.directDependenciesMap = dependencyModule.getExplicitDependenciesMap(); - this.platformClasses = platformClasses; + this.platformJars = platformJars; + this.fileManager = fileManager; } Set<ClassSymbol> getSeenClasses() { @@ -236,7 +241,7 @@ public final class StrictJavaDepsPlugin extends BlazeJavaCompilerPlugin { } Symbol.TypeSymbol sym = node.type.tsym; - String jarName = getJarName(sym.enclClass(), platformClasses); + String jarName = getJarName(fileManager, sym.enclClass(), platformJars); // If this type symbol comes from a class file loaded from a jar, check // whether that jar was a direct dependency and error out otherwise. @@ -381,26 +386,32 @@ public final class StrictJavaDepsPlugin extends BlazeJavaCompilerPlugin { * Returns the name of the jar file from which the given class symbol was * loaded, if available, and null otherwise. Implicitly filters out jars * from the compilation bootclasspath. - * @param platformClasses classes on javac's bootclasspath + * @param platformJars jars on javac's bootclasspath */ - static String getJarName(ClassSymbol classSymbol, Set<JavaFileObject> platformClasses) { - if (classSymbol != null) { - // Ignore symbols that appear in the sourcepath: - if (haveSourceForSymbol(classSymbol)) { - return null; - } - JavaFileObject classfile = unwrapFileObject(classSymbol.classfile); - if (classfile instanceof ZipArchive.ZipFileObject - || classfile instanceof ZipFileIndexArchive.ZipFileIndexFileObject) { - String name = classfile.getName(); - // Here name will be something like blaze-out/.../com/foo/libfoo.jar(Bar.class) - String jarName = name.split("\\(")[0]; - if (!platformClasses.contains(classfile)) { - return jarName; - } - } + static String getJarName( + JavaFileManager fileManager, ClassSymbol classSymbol, Set<String> platformJars) { + if (classSymbol == null) { + return null; + } + + // Ignore symbols that appear in the sourcepath: + if (haveSourceForSymbol(classSymbol)) { + return null; } - return null; + + JavaFileObject classfile = unwrapFileObject(classSymbol.classfile); + + String name = ImplicitDependencyExtractor.getJarName(fileManager, classfile); + if (name == null) { + return null; + } + + // Filter out classes in rt.jar + if (platformJars.contains(classfile)) { + return null; + } + + return name; } /** |