src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/Dependencies.java

Print this page
rev 2819 : imported patch my-classpath-deps-00

@@ -23,23 +23,29 @@
  * questions.
  */
 
 package com.sun.tools.sjavac.comp;
 
-import javax.lang.model.element.Element;
-import java.util.Arrays;
-import java.util.Comparator;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.lang.model.element.Element;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
 
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
-import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.code.Symbol.TypeSymbol;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Name;
+import com.sun.tools.sjavac.Util;
+import com.sun.tools.sjavac.pubapi.PubApi;
 
 /** Utility class containing dependency information between packages
  *  and the pubapi for a package.
  *
  *  <p><b>This is NOT part of any supported API.

@@ -50,20 +56,21 @@
 public class Dependencies {
     protected static final Context.Key<Dependencies> dependenciesKey = new Context.Key<>();
 
     // The log to be used for error reporting.
     protected Log log;
-    // Map from package name to packages that the package depends upon.
-    protected Map<Name,Set<Name>> deps;
-    // This is the set of all packages that are supplied
-    // through the java files at the command line.
-    protected Set<Name> explicitPackages;
 
-    // Map from a package name to its public api.
+    // CompilationUnit -> Fully qualified type -> set of dependencies
+    protected Map<JCCompilationUnit, Map<String, Set<TypeSymbol>>> deps = new HashMap<>();
+
+    // CompilationUnit -> Fully qualified type -> set of dependencies
+    protected Map<JCCompilationUnit, Map<String, Set<TypeSymbol>>> cpDeps = new HashMap<>();
+
+    // Map from a class name to its public api.
     // Will the Name encode the module in the future?
     // If not, this will have to change to map from Module+Name to public api.
-    protected Map<Name,StringBuffer> publicApiPerClass;
+    protected Map<ClassSymbol, PubApi> publicApiPerClass = new HashMap<>();
 
     public static Dependencies instance(Context context) {
         Dependencies instance = context.get(dependenciesKey);
         if (instance == null)
             instance = new Dependencies(context);

@@ -71,111 +78,100 @@
     }
 
     private Dependencies(Context context) {
         context.put(dependenciesKey, this);
         log = Log.instance(context);
-        deps = new HashMap<>();
-        explicitPackages = new HashSet<>();
-        publicApiPerClass = new HashMap<>();
     }
 
     /**
-     * Fetch the set of dependencies that are relevant to the compile
-     * that has just been performed. I.e. we are only interested in
-     * dependencies for classes that were explicitly compiled.
-     * @return
+     * Convert the map from class names to their pubapi to a map
+     * from package names to their pubapi.
      */
-    public Map<String,Set<String>> getDependencies() {
-        Map<String,Set<String>> new_deps = new HashMap<>();
-        if (explicitPackages == null) return new_deps;
-        for (Name pkg : explicitPackages) {
-            Set<Name> set = deps.get(pkg);
-            if (set != null) {
-                Set<String> new_set = new_deps.get(pkg.toString());
-                if (new_set == null) {
-                    new_set = new HashSet<>();
-                    // Modules beware....
-                    new_deps.put(":"+pkg.toString(), new_set);
-                }
-                for (Name d : set) {
-                    new_set.add(":"+d.toString());
-                }
-            }
-        }
-        return new_deps;
-    }
+    public Map<String, PubApi> getPubapis(Collection<JavaFileObject> explicitJFOs, boolean explicits) {
 
-    static class CompareNames implements Comparator<Name> {
-         public int compare(Name a, Name b) {
-             return a.toString().compareTo(b.toString());
-         }
+        // Maps ":java.lang" to a package level pub api (with only types on top level)
+        Map<String, PubApi> result = new HashMap<>();
+        for (ClassSymbol cs : publicApiPerClass.keySet()) {
+            
+            boolean amongExplicits = explicitJFOs.contains(cs.sourcefile);
+            if (explicits != amongExplicits)
+                continue;
 
+            String pkg = ":" + cs.packge().fullname;
+            PubApi currentPubApi = result.getOrDefault(pkg, new PubApi());
+            result.put(pkg, PubApi.mergeTypes(currentPubApi, publicApiPerClass.get(cs)));
     }
 
-    /**
-     * Convert the map from class names to their pubapi to a map
-     * from package names to their pubapi (which is the sorted concatenation
-     * of all the class pubapis)
-     */
-    public Map<String,String> getPubapis() {
-        Map<String,String> publicApiPerPackage = new HashMap<>();
-        if (publicApiPerClass == null) return publicApiPerPackage;
-        Name[] keys = publicApiPerClass.keySet().toArray(new Name[0]);
-        Arrays.sort(keys, new CompareNames());
-        StringBuffer newPublicApi = new StringBuffer();
-        int i=0;
-        String prevPkg = "";
-        for (Name k : keys) {
-            String cn = k.toString();
-            String pn = "";
-            int dp = cn.lastIndexOf('.');
-            if (dp != -1) {
-                pn = cn.substring(0,dp);
-            }
-            if (!pn.equals(prevPkg)) {
-                if (!prevPkg.equals("")) {
-                    // Add default module name ":"
-                    publicApiPerPackage.put(":"+prevPkg, newPublicApi.toString());
-                }
-                newPublicApi = new StringBuffer();
-                prevPkg = pn;
-            }
-            newPublicApi.append(publicApiPerClass.get(k));
-            i++;
-        }
-        if (!prevPkg.equals(""))
-            publicApiPerPackage.put(":"+prevPkg, newPublicApi.toString());
-        return publicApiPerPackage;
+        return result;
     }
 
     /**
-     * Visit the api of a class and construct a pubapi string and
+     * Visit the api of a class and construct a pubapi and
      * store it into the pubapi_perclass map.
      */
+    @SuppressWarnings("deprecation")
     public void visitPubapi(Element e) {
-        Name n = ((ClassSymbol)e).fullname;
-        Name p = ((ClassSymbol)e).packge().fullname;
-        StringBuffer sb = publicApiPerClass.get(n);
-        Assert.check(sb == null);
-        sb = new StringBuffer();
-        PubapiVisitor v = new PubapiVisitor(sb);
+
+        // Skip anonymous classes for now
+        if (e == null)
+            return;
+
+        PubapiVisitor v = new PubapiVisitor();
         v.visit(e);
-        if (sb.length()>0) {
-            publicApiPerClass.put(n, sb);
+        publicApiPerClass.put((ClassSymbol) e, v.getCollectedPubApi());
         }
-        explicitPackages.add(p);
+
+    public void collect(Location loc, JCCompilationUnit cu, String from, TypeSymbol toSym) {
+
+        Map<JCCompilationUnit, Map<String, Set<TypeSymbol>>> depsMap;
+
+        // TODO: Just because it's not CLASS_PATH doesn't mean it's to-be-compiled path
+        depsMap = loc == StandardLocation.CLASS_PATH ? cpDeps : deps;
+
+        if (!depsMap.containsKey(cu))
+            depsMap.put(cu, new HashMap<>());
+        Map<String, Set<TypeSymbol>> map = depsMap.get(cu);
+        map.merge(from, Collections.singleton(toSym), Util::union);
      }
 
-    /**
-     * Collect a dependency. curr_pkg is marked as depending on dep_pkg.
-     */
-    public void collect(Name currPkg, Name depPkg) {
-        if (!currPkg.equals(depPkg)) {
-            Set<Name> theset = deps.get(currPkg);
-            if (theset==null) {
-                theset = new HashSet<>();
-                deps.put(currPkg, theset);
+    // Package -> Type [from] -> Set of Type [to]
+    public Map<String, Map<String, Set<String>>> getDependencies(Collection<JavaFileObject> explicits) {
+        return getTypeDependenciesHelper(explicits, deps);
+    }
+    public Map<String, Map<String, Set<String>>> getCpDependencies(Collection<JavaFileObject> explicits) {
+        return getTypeDependenciesHelper(explicits, cpDeps);
             }
-            theset.add(depPkg);
+    public Map<String, Map<String, Set<String>>> getTypeDependenciesHelper(Collection<JavaFileObject> explicits,
+                                                                           Map<JCCompilationUnit, Map<String, Set<TypeSymbol>>> depsMap) {
+        Map<String, Map<String, Set<String>>> result = new HashMap<>();
+        for (JCCompilationUnit cu : depsMap.keySet()) {
+
+            if (!explicits.contains(cu.sourcefile))
+                continue;
+
+            // Dependencies to add to package entry
+            Map<String, Set<TypeSymbol>> src = depsMap.getOrDefault(cu, Collections.emptyMap());
+
+            // Sjavac does currently not handle default packages.
+            if (cu.getPackage() == null)
+                continue;
+
+            String key = ":" + cu.getPackage().packge.fullname.toString();
+
+            // Find (or create) destination
+            Map<String, Set<String>> dst;
+            if (result.containsKey(key))
+                dst = result.get(key);
+            else
+                result.put(key, dst = new HashMap<>());
+
+            for (String fqFrom : src.keySet()) {
+                dst.put(fqFrom, src.get(fqFrom)
+                                   .stream()
+                                   .map(ts -> ts.type.tsym.flatName().toString())
+                                   .collect(Collectors.toSet()));
         }
     }
+        return result;
+    }
+
 }