Mark unresolved classes in jdeps as Kind.INCOMPLETE.

Currently, all classes from the symbol table are added to jdeps,
even if some of them haven't been resolved and as such aren't
actually used. This causes siblings from other jars (such as
R.java) to be added to jdeps, even though they are not actually
referenced. Mark these with Kind.UNRESOLVED to allow code to
discard these.

All non-test code that references Kind.IMPLICIT has been
modified to also check for Kind.INCOMPLETE to keep
the current behavior unchanged.

Eg:

jar liba.jar:
package a;
class A {
  void test() {
    // Use R.id
  }
}

jar liba_resources.jar:
package a;
class R {
}

package b;
import a;
class MyClass {
  A a = new A();
}
---> jdeps will contain both liba.jar, liba_resources.jar
the latter will now have Kind.INCOMPLETE.

--
MOS_MIGRATED_REVID=133791687
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/DependencyModule.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/DependencyModule.java
index efb7a43..e5e8226 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/DependencyModule.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/DependencyModule.java
@@ -299,7 +299,9 @@
         throw new IOException("Could not parse Deps.Dependencies message from proto.");
       }
       for (Deps.Dependency dep : deps.getDependencyList()) {
-        if (dep.getKind() == Kind.EXPLICIT || dep.getKind() == Kind.IMPLICIT) {
+        if (dep.getKind() == Kind.EXPLICIT
+            || dep.getKind() == Kind.IMPLICIT
+            || dep.getKind() == Kind.INCOMPLETE) {
           requiredClasspath.add(dep.getPath());
         }
       }
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 07a9ff9..850d94b 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
@@ -50,29 +50,29 @@
   private final Set<String> depsSet;
   /** Map collecting dependency information, used for the proto output */
   private final Map<String, Deps.Dependency> depsMap;
+
   private final TypeVisitor typeVisitor = new TypeVisitor();
   private final JavaFileManager fileManager;
 
   /**
-   * ImplicitDependencyExtractor does not guarantee any ordering of the reported
-   * dependencies. Clients should preserve the original classpath ordering
-   * if trying to minimize their classpaths using this information.
+   * ImplicitDependencyExtractor does not guarantee any ordering of the reported dependencies.
+   * Clients should preserve the original classpath ordering if trying to minimize their classpaths
+   * using this information.
    */
-  public ImplicitDependencyExtractor(Set<String> depsSet, Map<String, Deps.Dependency> depsMap,
-      JavaFileManager fileManager) {
+  public ImplicitDependencyExtractor(
+      Set<String> depsSet, Map<String, Deps.Dependency> depsMap, JavaFileManager fileManager) {
     this.depsSet = depsSet;
     this.depsMap = depsMap;
     this.fileManager = fileManager;
   }
 
   /**
-   * Collects the implicit dependencies of the given set of ClassSymbol roots.
-   * As we're interested in differentiating between symbols that were just
-   * resolved vs. symbols that were fully completed by the compiler, we start
-   * the analysis by finding all the implicit dependencies reachable from the
-   * given set of roots. For completeness, we then walk the symbol table
-   * associated with the given context and collect the jar files of the
-   * remaining class symbols found there.
+   * Collects the implicit dependencies of the given set of ClassSymbol roots. As we're interested
+   * in differentiating between symbols that were just resolved vs. symbols that were fully
+   * completed by the compiler, we start the analysis by finding all the implicit dependencies
+   * reachable from the given set of roots. For completeness, we then walk the symbol table
+   * associated with the given context and collect the jar files of the remaining class symbols
+   * found there.
    *
    * @param context compilation context
    * @param roots root classes in the implicit dependency collection
@@ -92,17 +92,18 @@
 
     // Collect all other partially resolved types
     for (ClassSymbol cs : symtab.classes.values()) {
+      // When recording we want to differentiate between jar references through completed symbols
+      // and incomplete symbols
+      boolean completed = cs.isCompleted();
       if (cs.classfile != null) {
-        collectJarOf(cs.classfile, platformJars);
+        collectJarOf(cs.classfile, platformJars, completed);
       } else if (cs.sourcefile != null) {
-        collectJarOf(cs.sourcefile, platformJars);
+        collectJarOf(cs.sourcefile, platformJars, completed);
       }
     }
   }
 
-  /**
-   * Collect the set of jars on the compilation bootclasspath.
-   */
+  /** Collect the set of jars on the compilation bootclasspath. */
   public static Set<String> getPlatformJars(JavaFileManager fileManager) {
 
     if (fileManager instanceof StandardJavaFileManager) {
@@ -125,18 +126,19 @@
 
     // 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());
+    throw new IllegalStateException(
+        "Unsupported file manager type: " + fileManager.getClass().getName());
   }
 
   /**
-   * Attempts to add the jar associated with the given JavaFileObject, if any,
-   * to the collection, filtering out jars on the compilation bootclasspath.
+   * Attempts to add the jar associated with the given JavaFileObject, if any, to the collection,
+   * filtering out jars on the compilation bootclasspath.
    *
    * @param reference JavaFileObject representing a class or source file
    * @param platformJars classes on javac's bootclasspath
+   * @param completed whether the jar was referenced through a completed symbol
    */
-  private void collectJarOf(JavaFileObject reference, Set<String> platformJars) {
+  private void collectJarOf(JavaFileObject reference, Set<String> platformJars, boolean completed) {
 
     String name = getJarName(fileManager, reference);
     if (name == null) {
@@ -149,11 +151,18 @@
     }
 
     depsSet.add(name);
-    if (!depsMap.containsKey(name)) {
-      depsMap.put(name, Deps.Dependency.newBuilder()
-          .setKind(Deps.Dependency.Kind.IMPLICIT)
-          .setPath(name)
-          .build());
+    Deps.Dependency currentDep = depsMap.get(name);
+
+    // If the dep hasn't been recorded we add it to the map
+    // If it's been recorded as INCOMPLETE but is now complete we upgrade the dependency
+    if (currentDep == null
+        || (completed && currentDep.getKind() == Deps.Dependency.Kind.INCOMPLETE)) {
+      depsMap.put(
+          name,
+          Deps.Dependency.newBuilder()
+              .setKind(completed ? Deps.Dependency.Kind.IMPLICIT : Deps.Dependency.Kind.INCOMPLETE)
+              .setPath(name)
+              .build());
     }
   }
 
@@ -182,7 +191,6 @@
     return null;
   }
 
-
   private static class TypeVisitor extends SimpleTypeVisitor7<Void, Void> {
     // TODO(bazel-team): Override the visitor methods we're interested in.
   }
diff --git a/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java b/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java
index 395835e..2e6d453 100644
--- a/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java
+++ b/src/java_tools/buildjar/javatests/com/google/devtools/build/java/turbine/javac/JavacTurbineTest.java
@@ -407,8 +407,8 @@
         .containsExactlyEntriesIn(
             ImmutableMap.of(
                 libA.toString(), Deps.Dependency.Kind.EXPLICIT,
-                libB.toString(), Deps.Dependency.Kind.IMPLICIT,
-                libC.toString(), Deps.Dependency.Kind.IMPLICIT));
+                libB.toString(), Deps.Dependency.Kind.INCOMPLETE,
+                libC.toString(), Deps.Dependency.Kind.INCOMPLETE));
   }
 
   private Map<String, Deps.Dependency.Kind> getEntries(Deps.Dependencies deps) {
@@ -555,7 +555,7 @@
                   libA.toString(),
                   Deps.Dependency.Kind.EXPLICIT,
                   libB.toString(),
-                  Deps.Dependency.Kind.IMPLICIT));
+                  Deps.Dependency.Kind.INCOMPLETE));
     }
   }
 
diff --git a/src/main/protobuf/deps.proto b/src/main/protobuf/deps.proto
index af35bea..8c688a7 100644
--- a/src/main/protobuf/deps.proto
+++ b/src/main/protobuf/deps.proto
@@ -36,6 +36,8 @@
     IMPLICIT = 1;
     // Unused dependency.
     UNUSED = 2;
+    // Implicit dependency considered by the compiler but not completed.
+    INCOMPLETE = 3;
   }
 
   // Path to the artifact representing this dependency.