langtools/src/share/classes/com/sun/tools/javac/util/GraphUtils.java
author briangoetz
Wed, 18 Dec 2013 10:29:25 -0500
changeset 22159 682da512ec17
parent 20249 93f8eae31092
child 25844 48eab270456c
permissions -rw-r--r--
8030253: Update langtools to use strings-in-switch 8030262: Update langtools to use foreach loops 8030245: Update langtools to use try-with-resources and multi-catch Reviewed-by: darcy
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     1
/*
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     2
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     4
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    10
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    15
 * accompanied this code).
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    16
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    20
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    23
 * questions.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    24
 */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    25
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    26
package com.sun.tools.javac.util;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    27
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    28
/** <p><b>This is NOT part of any supported API.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    29
 *  If you write code that depends on this, you do so at your own risk.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    30
 *  This code and its internal interfaces are subject to change or
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    31
 *  deletion without notice.</b>
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    32
 */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    33
public class GraphUtils {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    34
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    35
    /**
19914
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    36
     * Basic interface for defining various dependency kinds. All dependency kinds
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    37
     * must at least support basic capabilities to tell the DOT engine how to render them.
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    38
     */
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    39
    public interface DependencyKind {
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    40
        /**
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    41
         * Returns the DOT representation (to be used in a {@code style} attribute
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    42
         * that's most suited for this dependency kind.
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    43
         */
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    44
        String getDotStyle();
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    45
    }
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    46
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    47
    /**
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    48
     * This class is a basic abstract class for representing a node.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    49
     * A node is associated with a given data.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    50
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    51
    public static abstract class Node<D> {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    52
        public final D data;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    53
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    54
        public Node(D data) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    55
            this.data = data;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    56
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    57
19914
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    58
        /**
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    59
         * Get an array of the dependency kinds supported by this node.
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    60
         */
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    61
        public abstract DependencyKind[] getSupportedDependencyKinds();
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    62
19914
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    63
        /**
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    64
         * Get all dependencies, regardless of their kind.
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    65
         */
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    66
        public abstract Iterable<? extends Node<D>> getAllDependencies();
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    67
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    68
        /**
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    69
         * Get a name for the dependency (of given kind) linking this node to a given node
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    70
         */
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    71
        public abstract String getDependencyName(Node<D> to, DependencyKind dk);
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    72
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    73
        @Override
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    74
        public String toString() {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    75
            return data.toString();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    76
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    77
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    78
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    79
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    80
     * This class specialized Node, by adding elements that are required in order
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    81
     * to perform Tarjan computation of strongly connected components.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    82
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    83
    public static abstract class TarjanNode<D> extends Node<D> implements Comparable<TarjanNode<D>> {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    84
        int index = -1;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    85
        int lowlink;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    86
        boolean active;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    87
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    88
        public TarjanNode(D data) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    89
            super(data);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    90
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    91
19914
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    92
        public abstract Iterable<? extends TarjanNode<D>> getAllDependencies();
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    93
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
    94
        public abstract Iterable<? extends TarjanNode<D>> getDependenciesByKind(DependencyKind dk);
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    95
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    96
        public int compareTo(TarjanNode<D> o) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    97
            return (index < o.index) ? -1 : (index == o.index) ? 0 : 1;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    98
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    99
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   100
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   101
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   102
     * Tarjan's algorithm to determine strongly connected components of a
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   103
     * directed graph in linear time. Works on TarjanNode.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   104
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   105
    public static <D, N extends TarjanNode<D>> List<? extends List<? extends N>> tarjan(Iterable<? extends N> nodes) {
20249
93f8eae31092 6386236: Please rename com.sun.tools.javac.util.ListBuffer.lb()
alundblad
parents: 19914
diff changeset
   106
        ListBuffer<List<N>> cycles = new ListBuffer<>();
93f8eae31092 6386236: Please rename com.sun.tools.javac.util.ListBuffer.lb()
alundblad
parents: 19914
diff changeset
   107
        ListBuffer<N> stack = new ListBuffer<>();
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   108
        int index = 0;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   109
        for (N node: nodes) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   110
            if (node.index == -1) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   111
                index += tarjan(node, index, stack, cycles);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   112
            }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   113
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   114
        return cycles.toList();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   115
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   116
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   117
    private static <D, N extends TarjanNode<D>> int tarjan(N v, int index, ListBuffer<N> stack, ListBuffer<List<N>> cycles) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   118
        v.index = index;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   119
        v.lowlink = index;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   120
        index++;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   121
        stack.prepend(v);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   122
        v.active = true;
19914
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
   123
        for (TarjanNode<D> nd: v.getAllDependencies()) {
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   124
            @SuppressWarnings("unchecked")
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   125
            N n = (N)nd;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   126
            if (n.index == -1) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   127
                tarjan(n, index, stack, cycles);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   128
                v.lowlink = Math.min(v.lowlink, n.lowlink);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   129
            } else if (stack.contains(n)) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   130
                v.lowlink = Math.min(v.lowlink, n.index);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   131
            }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   132
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   133
        if (v.lowlink == v.index) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   134
            N n;
20249
93f8eae31092 6386236: Please rename com.sun.tools.javac.util.ListBuffer.lb()
alundblad
parents: 19914
diff changeset
   135
            ListBuffer<N> cycle = new ListBuffer<>();
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   136
            do {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   137
                n = stack.remove();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   138
                n.active = false;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   139
                cycle.add(n);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   140
            } while (n != v);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   141
            cycles.add(cycle.toList());
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   142
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   143
        return index;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   144
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   145
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   146
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   147
     * Debugging: dot representation of a set of connected nodes. The resulting
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   148
     * dot representation will use {@code Node.toString} to display node labels
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   149
     * and {@code Node.printDependency} to display edge labels. The resulting
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   150
     * representation is also customizable with a graph name and a header.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   151
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   152
    public static <D> String toDot(Iterable<? extends TarjanNode<D>> nodes, String name, String header) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   153
        StringBuilder buf = new StringBuilder();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   154
        buf.append(String.format("digraph %s {\n", name));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   155
        buf.append(String.format("label = \"%s\";\n", header));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   156
        //dump nodes
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   157
        for (TarjanNode<D> n : nodes) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   158
            buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.toString()));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   159
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   160
        //dump arcs
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   161
        for (TarjanNode<D> from : nodes) {
19914
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
   162
            for (DependencyKind dk : from.getSupportedDependencyKinds()) {
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
   163
                for (TarjanNode<D> to : from.getDependenciesByKind(dk)) {
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
   164
                    buf.append(String.format("%s -> %s [label = \" %s \" style = %s ];\n",
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
   165
                            from.hashCode(), to.hashCode(), from.getDependencyName(to, dk), dk.getDotStyle()));
d86271bd430a 8016177: structural most specific and stuckness
vromero
parents: 15717
diff changeset
   166
                }
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   167
            }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   168
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   169
        buf.append("}\n");
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   170
        return buf.toString();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   171
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   172
}