Include the supertype closure of used types in jdeps
MOE_MIGRATED_REVID=138526825
diff --git a/java/com/google/turbine/deps/Dependencies.java b/java/com/google/turbine/deps/Dependencies.java
index 740ae2b..b6aeb6a 100644
--- a/java/com/google/turbine/deps/Dependencies.java
+++ b/java/com/google/turbine/deps/Dependencies.java
@@ -19,10 +19,16 @@
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.turbine.binder.Binder.BindingResult;
+import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bytecode.BytecodeBoundClass;
+import com.google.turbine.binder.env.CompoundEnv;
+import com.google.turbine.binder.env.Env;
+import com.google.turbine.binder.env.SimpleEnv;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.lower.Lower.Lowered;
import com.google.turbine.proto.DepsProto;
+import java.util.LinkedHashSet;
+import java.util.Set;
/** Support for Bazel jdeps dependency output. */
public class Dependencies {
@@ -33,7 +39,9 @@
BindingResult bound,
Lowered lowered) {
DepsProto.Dependencies.Builder deps = DepsProto.Dependencies.newBuilder();
- for (ClassSymbol sym : lowered.symbols()) {
+ Set<ClassSymbol> closure = superTypeClosure(bound, lowered);
+ Set<String> jars = new LinkedHashSet<>();
+ for (ClassSymbol sym : closure) {
BytecodeBoundClass info = bound.classPathEnv().get(sym);
if (info == null) {
// the symbol wasn't loaded from the classpath
@@ -44,6 +52,9 @@
// bootclasspath deps are not tracked
continue;
}
+ jars.add(jarFile);
+ }
+ for (String jarFile : jars) {
deps.addDependency(
DepsProto.Dependency.newBuilder()
.setPath(jarFile)
@@ -56,4 +67,32 @@
}
return deps.build();
}
+
+ private static Set<ClassSymbol> superTypeClosure(BindingResult bound, Lowered lowered) {
+ Env<ClassSymbol, TypeBoundClass> env =
+ CompoundEnv.<ClassSymbol, TypeBoundClass>of(new SimpleEnv<>(bound.units()))
+ .append(bound.classPathEnv());
+ Set<ClassSymbol> closure = new LinkedHashSet<>();
+ for (ClassSymbol sym : lowered.symbols()) {
+ addSuperTypes(closure, env, sym);
+ }
+ return closure;
+ }
+
+ private static void addSuperTypes(
+ Set<ClassSymbol> closure, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym) {
+ if (!closure.add(sym)) {
+ return;
+ }
+ TypeBoundClass info = env.get(sym);
+ if (info == null) {
+ return;
+ }
+ if (info.superclass() != null) {
+ addSuperTypes(closure, env, info.superclass());
+ }
+ for (ClassSymbol i : info.interfaces()) {
+ addSuperTypes(closure, env, i);
+ }
+ }
}
diff --git a/javatests/com/google/turbine/deps/DependenciesTest.java b/javatests/com/google/turbine/deps/DependenciesTest.java
index 9932d0e..71579f5 100644
--- a/javatests/com/google/turbine/deps/DependenciesTest.java
+++ b/javatests/com/google/turbine/deps/DependenciesTest.java
@@ -143,7 +143,11 @@
Path libb =
new LibraryBuilder()
.setClasspath(liba)
- .addSourceLines("B.java", "class B extends A {}")
+ .addSourceLines(
+ "B.java", //
+ "class B {",
+ " public static final A a = new A();",
+ "}")
.compileToJar("libb.jar");
DepsProto.Dependencies deps =
new DepsBuilder()
@@ -184,4 +188,65 @@
libb, DepsProto.Dependency.Kind.EXPLICIT,
liba, DepsProto.Dependency.Kind.EXPLICIT));
}
+
+ @Test
+ public void closure() throws Exception {
+ Path libi =
+ new LibraryBuilder()
+ .addSourceLines(
+ "i/I.java",
+ "package i;", //
+ "public interface I {}")
+ .compileToJar("libi.jar");
+ Path liba =
+ new LibraryBuilder()
+ .setClasspath(libi)
+ .addSourceLines(
+ "a/A.java", //
+ "package a;",
+ "import i.I;",
+ "public class A implements I {}")
+ .compileToJar("liba.jar");
+ Path libb =
+ new LibraryBuilder()
+ .setClasspath(liba, libi)
+ .addSourceLines(
+ "b/B.java", //
+ "package b;",
+ "import a.A;",
+ "public class B extends A {}")
+ .compileToJar("libb.jar");
+ {
+ DepsProto.Dependencies deps =
+ new DepsBuilder()
+ .setClasspath(liba, libb, libi)
+ .addSourceLines(
+ "Test.java", //
+ "import b.B;",
+ "class Test extends B {}")
+ .run();
+ assertThat(depsMap(deps))
+ .isEqualTo(
+ ImmutableMap.of(
+ libi, DepsProto.Dependency.Kind.EXPLICIT,
+ libb, DepsProto.Dependency.Kind.EXPLICIT,
+ liba, DepsProto.Dependency.Kind.EXPLICIT));
+ }
+ {
+ // partial classpath
+ DepsProto.Dependencies deps =
+ new DepsBuilder()
+ .setClasspath(liba, libb)
+ .addSourceLines(
+ "Test.java", //
+ "import b.B;",
+ "class Test extends B {}")
+ .run();
+ assertThat(depsMap(deps))
+ .isEqualTo(
+ ImmutableMap.of(
+ libb, DepsProto.Dependency.Kind.EXPLICIT,
+ liba, DepsProto.Dependency.Kind.EXPLICIT));
+ }
+ }
}