8087349: Test tools/sjavac/IncCompInheritance.java is failing
authoralundblad
Thu, 22 Oct 2015 09:05:54 +0200
changeset 33366 a113e08cc061
parent 33365 b25c5559727e
child 33367 546ffcb790a5
8087349: Test tools/sjavac/IncCompInheritance.java is failing Summary: Refactoring of Dependencies framework. Reviewed-by: mcimadamore
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/dependencies/NewDependencyCollector.java
langtools/test/tools/javac/importscope/dependencies/DependenciesTest.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Oct 21 18:40:01 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 22 09:05:54 2015 +0200
@@ -56,7 +56,6 @@
 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
-import com.sun.tools.javac.util.Dependencies.AttributionKind;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
 import com.sun.tools.javac.util.List;
@@ -760,7 +759,6 @@
      */
     void attribTypeVariables(List<JCTypeParameter> typarams, Env<AttrContext> env) {
         for (JCTypeParameter tvar : typarams) {
-            dependencies.push(AttributionKind.TVAR, tvar);
             TypeVar a = (TypeVar)tvar.type;
             a.tsym.flags_field |= UNATTRIBUTED;
             a.bound = Type.noType;
@@ -775,7 +773,6 @@
                 types.setBounds(a, List.of(syms.objectType));
             }
             a.tsym.flags_field &= ~UNATTRIBUTED;
-            dependencies.pop();
         }
         for (JCTypeParameter tvar : typarams) {
             chk.checkNonCyclic(tvar.pos(), (TypeVar)tvar.type);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Wed Oct 21 18:40:01 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Oct 22 09:05:54 2015 +0200
@@ -54,7 +54,6 @@
 import static com.sun.tools.javac.code.TypeTag.ERROR;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
-import com.sun.tools.javac.util.Dependencies.AttributionKind;
 import com.sun.tools.javac.util.Dependencies.CompletionCause;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -372,7 +371,6 @@
         }
 
         private void doImport(JCImport tree) {
-            dependencies.push(AttributionKind.IMPORT, tree);
             JCFieldAccess imp = (JCFieldAccess)tree.qualid;
             Name name = TreeInfo.name(imp);
 
@@ -399,7 +397,6 @@
                     importNamed(tree.pos(), c, env, tree);
                 }
             }
-            dependencies.pop();
         }
 
         Type attribImportType(JCTree tree, Env<AttrContext> env) {
@@ -647,13 +644,7 @@
 
             if (tree.extending != null) {
                 extending = clearTypeParams(tree.extending);
-                dependencies.push(AttributionKind.EXTENDS, tree.extending);
-                try {
-                    supertype = attr.attribBase(extending, baseEnv,
-                                                true, false, true);
-                } finally {
-                    dependencies.pop();
-                }
+                supertype = attr.attribBase(extending, baseEnv, true, false, true);
             } else {
                 extending = null;
                 supertype = ((tree.mods.flags & Flags.ENUM) != 0)
@@ -671,20 +662,14 @@
             List<JCExpression> interfaceTrees = tree.implementing;
             for (JCExpression iface : interfaceTrees) {
                 iface = clearTypeParams(iface);
-                dependencies.push(AttributionKind.IMPLEMENTS, iface);
-                try {
-                    Type it = attr.attribBase(iface, baseEnv, false, true, true);
-                    if (it.hasTag(CLASS)) {
-                        interfaces.append(it);
-                        if (all_interfaces != null) all_interfaces.append(it);
-                    } else {
-                        if (all_interfaces == null)
-                            all_interfaces = new ListBuffer<Type>().appendList(interfaces);
-                        all_interfaces.append(modelMissingTypes(it, iface, true));
-
-                    }
-                } finally {
-                    dependencies.pop();
+                Type it = attr.attribBase(iface, baseEnv, false, true, true);
+                if (it.hasTag(CLASS)) {
+                    interfaces.append(it);
+                    if (all_interfaces != null) all_interfaces.append(it);
+                } else {
+                    if (all_interfaces == null)
+                        all_interfaces = new ListBuffer<Type>().appendList(interfaces);
+                    all_interfaces.append(modelMissingTypes(it, iface, true));
                 }
             }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Wed Oct 21 18:40:01 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Thu Oct 22 09:05:54 2015 +0200
@@ -30,7 +30,7 @@
 import com.sun.tools.javac.code.Symbol.Completer;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.util.GraphUtils.DependencyKind;
 import com.sun.tools.javac.util.GraphUtils.DotVisitor;
 import com.sun.tools.javac.util.GraphUtils.NodeVisitor;
 
@@ -42,13 +42,13 @@
 import java.util.Collection;
 import java.util.EnumMap;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.Set;
 import java.util.Stack;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.tools.JavaFileObject;
 
@@ -78,69 +78,23 @@
     }
 
     /**
-     * This enum models different kinds of attribution actions triggered during
-     * symbol completion.
-     */
-    public enum AttributionKind {
-        /**
-         * Attribution of superclass (i.e. @{code extends} clause).
-         */
-        EXTENDS {
-            @Override
-            String format(JCTree tree) {
-                return "extends " + super.format(tree);
-            }
-        },
-        /**
-         * Attribution of superinterface (i.e. an type in the @{code interface} clause).
-         */
-        IMPLEMENTS {
-            @Override
-            String format(JCTree tree) {
-                return "implements " + super.format(tree);
-            }
-        },
-        /**
-         * Attribution of an import statement
-         */
-        IMPORT,
-        /**
-         * Attribution of type-variable bound
-         */
-        TVAR {
-            @Override
-            String format(JCTree tree) {
-                return "<" + super.format(tree) + ">";
-            }
-        };
-
-        String format(JCTree tree) {
-            return tree.toString();
-        }
-    }
-
-    /**
      * Push a new completion node on the stack.
      */
     abstract public void push(ClassSymbol s, CompletionCause phase);
 
     /**
-     * Push a new attribution node on the stack.
-     */
-    abstract public void push(AttributionKind ak, JCTree t);
-
-    /**
      * Remove current dependency node from the stack.
      */
     abstract public void pop();
 
-    public enum CompletionCause {
+    public enum CompletionCause implements GraphUtils.DependencyKind {
         CLASS_READER,
         HEADER_PHASE,
         HIERARCHY_PHASE,
         IMPORTS_PHASE,
         MEMBER_ENTER,
-        MEMBERS_PHASE;
+        MEMBERS_PHASE,
+        OTHER;
     }
 
     /**
@@ -163,13 +117,8 @@
         /**
          * Register a Context.Factory to create a Dependencies.
          */
-        public static void preRegister(final Context context) {
-            context.put(dependenciesKey, new Context.Factory<Dependencies>() {
-                public Dependencies make(Context c) {
-                    Dependencies deps = new GraphDependencies(context);
-                    return deps;
-                }
-            });
+        public static void preRegister(Context context) {
+            context.put(dependenciesKey, (Context.Factory<Dependencies>) GraphDependencies::new);
         }
 
         /**
@@ -195,12 +144,11 @@
         enum DependenciesMode {
             SOURCE("source"),
             CLASS("class"),
-            REDUNDANT("redundant"),
-            SIDE_EFFECTS("side-effects");
+            REDUNDANT("redundant");
 
             final String opt;
 
-            private DependenciesMode(String opt) {
+            DependenciesMode(String opt) {
                 this.opt = opt;
             }
 
@@ -228,46 +176,19 @@
         }
 
         /**
-         * Class representing a node in the dependency graph. Nodes are of two main
-         * kinds: (i) symbol nodes, corresponding to symbol completion requests
-         * (either from source or classfile); (ii) attribution nodes, corresponding to
-         * attribution actions triggered during (source) completion.
+         * Class representing a node in the dependency graph.
          */
-        public static abstract class Node extends GraphUtils.AbstractNode<String, Node>
-                implements GraphUtils.DottableNode<String, Node> {
-
-            /**
-             * Model the dependencies between nodes.
-             */
-            public enum DependencyKind implements GraphUtils.DependencyKind {
-                /**
-                 * standard dependency - i.e. completion of the source node depends
-                 * on completion of the sink node.
-                 */
-                REQUIRES("solid"),
-                /**
-                 * soft dependencies - i.e. completion of the source node depends
-                 * on side-effects of the source node. These dependencies are meant
-                 * to capture the order in which javac processes all dependants of a given node.
-                 */
-                SIDE_EFFECTS("dashed");
-
-                final String dotStyle;
-
-                DependencyKind(String dotStyle) {
-                    this.dotStyle = dotStyle;
-                }
-            }
-
+        public static abstract class Node extends GraphUtils.AbstractNode<ClassSymbol, Node>
+                implements GraphUtils.DottableNode<ClassSymbol, Node> {
             /**
              * dependant nodes grouped by kind
              */
-            EnumMap<DependencyKind, List<Node>> depsByKind;
+            EnumMap<CompletionCause, List<Node>> depsByKind;
 
-            Node(String value) {
+            Node(ClassSymbol value) {
                 super(value);
-                this.depsByKind = new EnumMap<>(DependencyKind.class);
-                for (DependencyKind depKind : DependencyKind.values()) {
+                this.depsByKind = new EnumMap<>(CompletionCause.class);
+                for (CompletionCause depKind : CompletionCause.values()) {
                     depsByKind.put(depKind, new ArrayList<Node>());
                 }
             }
@@ -281,8 +202,7 @@
 
             @Override
             public boolean equals(Object obj) {
-                return obj instanceof Node &&
-                        data.equals(((Node) obj).data);
+                return obj instanceof Node && data.equals(((Node) obj).data);
             }
 
             @Override
@@ -292,19 +212,12 @@
 
             @Override
             public GraphUtils.DependencyKind[] getSupportedDependencyKinds() {
-                return DependencyKind.values();
+                return CompletionCause.values();
             }
 
             @Override
-            public java.util.Collection<? extends Node> getDependenciesByKind(GraphUtils.DependencyKind dk) {
-                List<Node> deps = depsByKind.get(dk);
-                if (dk == DependencyKind.REQUIRES) {
-                    return deps;
-                } else {
-                    Set<Node> temp = new HashSet<>(deps);
-                    temp.removeAll(depsByKind.get(DependencyKind.REQUIRES));
-                    return temp;
-                }
+            public java.util.Collection<? extends Node> getDependenciesByKind(DependencyKind dk) {
+                return depsByKind.get(dk);
             }
 
             @Override
@@ -317,9 +230,14 @@
             @Override
             public Properties dependencyAttributes(Node to, GraphUtils.DependencyKind dk) {
                 Properties p = new Properties();
-                p.put("style", ((DependencyKind) dk).dotStyle);
+                p.put("label", dk);
                 return p;
             }
+
+            @Override
+            public String toString() {
+                return data.getQualifiedName().toString();
+            }
         }
 
         /**
@@ -349,11 +267,9 @@
             }
 
             final Kind ck;
-            final ClassSymbol sym;
 
             CompletionNode(ClassSymbol sym) {
-                super(sym.getQualifiedName().toString());
-                this.sym = sym;
+                super(sym);
                 //infer completion kind by looking at the symbol fields
                 boolean fromClass = (sym.classfile == null && sym.sourcefile == null) ||
                         (sym.classfile != null && sym.classfile.getKind() == JavaFileObject.Kind.CLASS);
@@ -371,27 +287,7 @@
             }
 
             public ClassSymbol getClassSymbol() {
-                return sym;
-            }
-        }
-
-        /**
-         * This is a dependency node used to model attribution actions triggered during
-         * source symbol completion. The possible kinds of attribution actions are
-         * captured in {@link AttributionNode}.
-         */
-        static class AttributionNode extends Node {
-
-            AttributionNode(AttributionKind ak, JCTree tree) {
-                super(ak.format(tree));
-            }
-
-            @Override
-            public Properties nodeAttributes() {
-                Properties p = super.nodeAttributes();
-                p.put("shape", "box");
-                p.put("style", "solid");
-                return p;
+                return data;
             }
         }
 
@@ -403,25 +299,20 @@
         /**
          * map containing all dependency nodes seen so far
          */
-        Map<String, Node> dependencyNodeMap = new LinkedHashMap<>();
+        Map<ClassSymbol, Node> dependencyNodeMap = new LinkedHashMap<>();
 
         @Override
         public void push(ClassSymbol s, CompletionCause phase) {
             Node n = new CompletionNode(s);
-            if (n == push(n)) {
+            if (n == push(n, phase)) {
                 s.completer = this;
             }
         }
 
-        @Override
-        public void push(AttributionKind ak, JCTree t) {
-            push(new AttributionNode(ak, t));
-        }
-
         /**
          * Push a new dependency on the stack.
          */
-        protected Node push(Node newNode) {
+        protected Node push(Node newNode, CompletionCause cc) {
             Node cachedNode = dependencyNodeMap.get(newNode.data);
             if (cachedNode == null) {
                 dependencyNodeMap.put(newNode.data, newNode);
@@ -430,7 +321,7 @@
             }
             if (!nodeStack.isEmpty()) {
                 Node currentNode = nodeStack.peek();
-                currentNode.addDependency(Node.DependencyKind.REQUIRES, newNode);
+                currentNode.addDependency(cc, newNode);
             }
             nodeStack.push(newNode);
             return newNode;
@@ -455,10 +346,6 @@
                 //filter source completions
                 new FilterVisitor(CompletionNode.Kind.CLASS).visit(dependencyNodeMap.values(), null);
             }
-            if (dependenciesModes.contains(DependenciesMode.SIDE_EFFECTS)) {
-                //add side-effects edges
-                new SideEffectVisitor().visit(dependencyNodeMap.values(), null);
-            }
             if (dependenciesFile != null) {
                 //write to file
                 try (FileWriter fw = new FileWriter(dependenciesFile)) {
@@ -469,7 +356,7 @@
 
         @Override
         public void complete(Symbol sym) throws CompletionFailure {
-            push((ClassSymbol) sym, null);
+            push((ClassSymbol)sym, CompletionCause.OTHER);
             pop();
             sym.completer = this;
         }
@@ -484,31 +371,9 @@
         }
 
         /**
-         * This visitor is used to generate the special side-effect dependencies
-         * given a graph containing only standard dependencies.
-         */
-        private static class SideEffectVisitor extends NodeVisitor<String, Node, Void> {
-            @Override
-            public void visitNode(Node node, Void arg) {
-                //do nothing
-            }
-
-            @Override
-            public void visitDependency(GraphUtils.DependencyKind dk, Node from, Node to, Void arg) {
-                //if we are adding multiple dependencies to same node
-                //make order explicit via special 'side-effect' dependencies
-                List<Node> deps = from.depsByKind.get(dk);
-                int pos = deps.indexOf(to);
-                if (dk == Node.DependencyKind.REQUIRES && pos > 0) {
-                    to.addDependency(Node.DependencyKind.SIDE_EFFECTS, deps.get(pos - 1));
-                }
-            }
-        }
-
-        /**
          * This visitor is used to prune the graph from spurious edges using some heuristics.
          */
-        private static class PruneVisitor extends NodeVisitor<String, Node, Void> {
+        private static class PruneVisitor extends NodeVisitor<ClassSymbol, Node, Void> {
             @Override
             public void visitNode(Node node, Void arg) {
                 //do nothing
@@ -517,8 +382,7 @@
             @Override
             public void visitDependency(GraphUtils.DependencyKind dk, Node from, Node to, Void arg) {
                 //heuristic - skips dependencies that are likely to be fake
-                if (from.equals(to) ||
-                        from.depsByKind.get(Node.DependencyKind.REQUIRES).contains(to)) {
+                if (from.equals(to)) {
                     to.depsByKind.get(dk).remove(from);
                 }
             }
@@ -527,7 +391,7 @@
         /**
          * This visitor is used to retain only completion nodes with given kind.
          */
-        private class FilterVisitor extends NodeVisitor<String, Node, Void> {
+        private class FilterVisitor extends NodeVisitor<ClassSymbol, Node, Void> {
 
             CompletionNode.Kind ck;
 
@@ -571,11 +435,6 @@
         }
 
         @Override
-        public void push(AttributionKind ak, JCTree t) {
-            //do nothing
-        }
-
-        @Override
         public void pop() {
             //do nothing
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/dependencies/NewDependencyCollector.java	Wed Oct 21 18:40:01 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/dependencies/NewDependencyCollector.java	Thu Oct 22 09:05:54 2015 +0200
@@ -26,11 +26,13 @@
 package com.sun.tools.sjavac.comp.dependencies;
 
 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 java.util.stream.Stream;
 
 import javax.tools.JavaFileManager.Location;
 import javax.tools.JavaFileObject;
@@ -38,7 +40,11 @@
 
 import com.sun.source.util.TaskEvent;
 import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.code.Kinds.Kind;
+import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.TypeSymbol;
+import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -85,7 +91,6 @@
 
         return deps.getNodes()
                    .stream()
-                   .filter(n -> n instanceof CompletionNode)
                    .map(n -> (CompletionNode) n)
                    .filter(n -> n.getClassSymbol().fullname != null)
                    .filter(n -> explicits == explicitJFOs.contains(n.getClassSymbol().classfile))
@@ -128,31 +133,66 @@
             String depPkg = Util.pkgNameOfClassName(fqDep);
 
             Map<String, Set<String>> depsForThisClass = result.get(depPkg);
-            if (depsForThisClass == null)
+            if (depsForThisClass == null) {
                 result.put(depPkg, depsForThisClass = new HashMap<>());
+            }
+
+            Set<String> fqDeps = depsForThisClass.get(fqDep);
+            if (fqDeps == null) {
+                depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
+            }
 
-            for (Node<?,?> depNode : cnode.getDependenciesByKind(GraphDependencies.Node.DependencyKind.REQUIRES)) {
-                boolean isCompletionNode = depNode instanceof CompletionNode;
-                if (isCompletionNode) {
-                    CompletionNode cDepNode = (CompletionNode) depNode;
-                    if (cDepNode == cnode)
-                        continue;
-                    if (cDepNode.getClassSymbol().fullname == null) // Anonymous class
-                        continue;
-                    Location depLoc = getLocationOf(cDepNode.getClassSymbol());
-                    boolean relevant = (cp  && depLoc == StandardLocation.CLASS_PATH)
-                                    || (!cp && depLoc == StandardLocation.SOURCE_PATH);
-                    if (!relevant)
-                        continue;
-
-                    Set<String> fqDeps = depsForThisClass.get(fqDep);
-                    if (fqDeps == null)
-                        depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
+            for (Node<?,?> depNode : getAllDependencies(cnode)) {
+                CompletionNode cDepNode = (CompletionNode) depNode;
+                // Symbol is not regarded to depend on itself.
+                if (cDepNode == cnode) {
+                    continue;
+                }
+                // Skip anonymous classes
+                if (cDepNode.getClassSymbol().fullname == null) {
+                    continue;
+                }
+                if (isSymbolRelevant(cp, cDepNode.getClassSymbol())) {
                     fqDeps.add(cDepNode.getClassSymbol().outermostClass().flatname.toString());
                 }
             }
+
+            // The completion dependency graph is not transitively closed for inheritance relations.
+            // For sjavac's purposes however, a class depends on it's super super type, so below we
+            // make sure that we include super types.
+            for (ClassSymbol cs : allSupertypes(cnode.getClassSymbol())) {
+                if (isSymbolRelevant(cp, cs)) {
+                    fqDeps.add(cs.outermostClass().flatname.toString());
+                }
+            }
+
         }
         return result;
     }
 
+    public boolean isSymbolRelevant(boolean cp, ClassSymbol cs) {
+        Location csLoc = getLocationOf(cs);
+        Location relevantLocation = cp ? StandardLocation.CLASS_PATH : StandardLocation.SOURCE_PATH;
+        return csLoc == relevantLocation;
+    }
+
+    private Set<ClassSymbol> allSupertypes(TypeSymbol t) {
+        if (t == null || !(t instanceof ClassSymbol)) {
+            return Collections.emptySet();
+        }
+        Set<ClassSymbol> result = new HashSet<>();
+        ClassSymbol cs = (ClassSymbol) t;
+        result.add(cs);
+        result.addAll(allSupertypes(cs.getSuperclass().tsym));
+        for (Type it : cs.getInterfaces()) {
+            result.addAll(allSupertypes(it.tsym));
+        }
+        return result;
+    }
+
+    private Collection<? extends Node<?, ?>> getAllDependencies(CompletionNode cnode) {
+        return Stream.of(cnode.getSupportedDependencyKinds())
+                     .flatMap(dk -> cnode.getDependenciesByKind(dk).stream())
+                     .collect(Collectors.toSet());
+    }
 }
--- a/langtools/test/tools/javac/importscope/dependencies/DependenciesTest.java	Wed Oct 21 18:40:01 2015 -0700
+++ b/langtools/test/tools/javac/importscope/dependencies/DependenciesTest.java	Thu Oct 22 09:05:54 2015 +0200
@@ -194,11 +194,6 @@
         }
 
         @Override
-        public void push(AttributionKind ak, JCTree t) {
-            inProcess.push(null);
-        }
-
-        @Override
         public void pop() {
             inProcess.pop();
         }