DPrinter.java revision 3831:209b0eab0e1f
133965Sjdp/*
278828Sobrien * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
3130561Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
433965Sjdp *
533965Sjdp * This code is free software; you can redistribute it and/or modify it
633965Sjdp * under the terms of the GNU General Public License version 2 only, as
733965Sjdp * published by the Free Software Foundation.
833965Sjdp *
933965Sjdp * This code is distributed in the hope that it will be useful, but WITHOUT
1033965Sjdp * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1133965Sjdp * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1233965Sjdp * version 2 for more details (a copy is included in the LICENSE file that
1333965Sjdp * accompanied this code).
1433965Sjdp *
1533965Sjdp * You should have received a copy of the GNU General Public License version
1633965Sjdp * 2 along with this work; if not, write to the Free Software Foundation,
1733965Sjdp * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1833965Sjdp *
1933965Sjdp * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2033965Sjdp * or visit www.oracle.com if you need additional information or have any
2133965Sjdp * questions.
2233965Sjdp */
2333965Sjdp
2433965Sjdp/* @test
2533965Sjdp * @bug 8043484 8007307
2633965Sjdp * @summary Make sure DPrinter.java compiles
2733965Sjdp * @modules jdk.compiler/com.sun.tools.javac.api
2833965Sjdp *          jdk.compiler/com.sun.tools.javac.code
2933965Sjdp *          jdk.compiler/com.sun.tools.javac.tree
3033965Sjdp *          jdk.compiler/com.sun.tools.javac.util
3133965Sjdp * @compile DPrinter.java
3233965Sjdp */
3333965Sjdp
3433965Sjdpimport java.io.File;
3533965Sjdpimport java.io.IOException;
3633965Sjdpimport java.io.PrintWriter;
3733965Sjdpimport java.lang.reflect.Field;
3833965Sjdpimport java.lang.reflect.Method;
3933965Sjdpimport java.util.ArrayList;
4033965Sjdpimport java.util.Arrays;
4133965Sjdpimport java.util.Collection;
4233965Sjdpimport java.util.EnumSet;
4377298Sobrienimport java.util.HashMap;
4433965Sjdpimport java.util.List;
4533965Sjdpimport java.util.Locale;
4633965Sjdpimport java.util.Map;
4733965Sjdpimport java.util.Set;
4833965Sjdp
4933965Sjdpimport javax.lang.model.element.Name;
5033965Sjdpimport javax.lang.model.element.TypeElement;
5133965Sjdpimport javax.tools.FileObject;
5233965Sjdpimport javax.tools.JavaCompiler;
5333965Sjdpimport javax.tools.JavaFileObject;
5433965Sjdpimport javax.tools.StandardJavaFileManager;
5533965Sjdpimport javax.tools.StandardLocation;
5633965Sjdpimport javax.tools.ToolProvider;
5733965Sjdp
5833965Sjdpimport com.sun.source.doctree.*;
5933965Sjdpimport com.sun.source.util.JavacTask;
6033965Sjdpimport com.sun.source.util.TaskEvent;
6133965Sjdpimport com.sun.source.util.TaskListener;
6233965Sjdpimport com.sun.source.util.Trees;
6333965Sjdpimport com.sun.tools.javac.api.JavacTrees;
6433965Sjdpimport com.sun.tools.javac.code.SymbolMetadata;
6533965Sjdpimport com.sun.tools.javac.code.Attribute;
6633965Sjdpimport com.sun.tools.javac.code.Flags;
6733965Sjdpimport com.sun.tools.javac.code.Kinds;
6833965Sjdpimport com.sun.tools.javac.code.Printer;
6933965Sjdpimport com.sun.tools.javac.code.Scope;
7033965Sjdpimport com.sun.tools.javac.code.Scope.CompoundScope;
7133965Sjdpimport com.sun.tools.javac.code.Symbol;
7233965Sjdpimport com.sun.tools.javac.code.Symbol.*;
7333965Sjdpimport com.sun.tools.javac.code.Type;
7433965Sjdpimport com.sun.tools.javac.code.Type.*;
7533965Sjdpimport com.sun.tools.javac.code.TypeTag;
7633965Sjdpimport com.sun.tools.javac.tree.JCTree;
7733965Sjdpimport com.sun.tools.javac.tree.JCTree.*;
7833965Sjdpimport com.sun.tools.javac.tree.Pretty;
7933965Sjdpimport com.sun.tools.javac.tree.TreeInfo;
8033965Sjdpimport com.sun.tools.javac.tree.TreeScanner;
8133965Sjdpimport com.sun.tools.javac.util.Assert;
8233965Sjdpimport com.sun.tools.javac.util.Context;
8333965Sjdpimport com.sun.tools.javac.util.Convert;
8433965Sjdpimport com.sun.tools.javac.util.Log;
8533965Sjdp
8633965Sjdp
8733965Sjdp/**
8833965Sjdp * Debug printer for javac internals, for when toString() just isn't enough.
8933965Sjdp *
9033965Sjdp * <p>
9133965Sjdp * The printer provides an API to generate structured views of javac objects,
9233965Sjdp * such as AST nodes, symbol, types and annotations. Various aspects of the
9391041Sobrien * output can be configured, such as whether to show nulls, empty lists, or
9491041Sobrien * a compressed representation of the source code. Visitors are used to walk
9591041Sobrien * object hierarchies, and can be replaced with custom visitors if the default
9691041Sobrien * visitors are not flexible enough.
9791041Sobrien *
9833965Sjdp * <p>
9933965Sjdp * In general, nodes are printed with an initial line identifying the node
10033965Sjdp * followed by indented lines for the child nodes. Currently, graphs are
10133965Sjdp * represented by printing a spanning subtree.
10233965Sjdp *
10333965Sjdp * <p>
10433965Sjdp * The printer can be accessed via a simple command-line utility,
10533965Sjdp * which makes it easy to see the internal representation of source code,
10633965Sjdp * such as simple test programs, during the compilation pipeline.
10733965Sjdp *
10833965Sjdp *  <p><b>This is NOT part of any supported API.
10933965Sjdp *  If you write code that depends on this, you do so at your own risk.
11033965Sjdp *  This code and its internal interfaces are subject to change or
11133965Sjdp *  deletion without notice.</b>
11233965Sjdp */
11333965Sjdp
11433965Sjdppublic class DPrinter {
11533965Sjdp    protected final PrintWriter out;
11633965Sjdp    protected final Trees trees;
11733965Sjdp    protected Printer printer;
11833965Sjdp    protected boolean showEmptyItems = true;
11960484Sobrien    protected boolean showNulls = true;
12060484Sobrien    protected boolean showPositions = false;
12160484Sobrien    protected boolean showSrc;
12260484Sobrien    protected boolean showTreeSymbols;
12360484Sobrien    protected boolean showTreeTypes;
12433965Sjdp    protected int maxSrcLength = 32;
12560484Sobrien    protected Locale locale = Locale.getDefault();
12660484Sobrien    protected static final String NULL = "#null";
12760484Sobrien
12860484Sobrien    // <editor-fold defaultstate="collapsed" desc="Configuration">
12989857Sobrien
13038889Sjdp    public static DPrinter instance(Context context) {
13191041Sobrien        DPrinter dp = context.get(DPrinter.class);
13238889Sjdp        if (dp == null) {
13338889Sjdp            dp = new DPrinter(context);
13489857Sobrien        }
13560484Sobrien        return dp;
13689857Sobrien
13733965Sjdp    }
13860484Sobrien
13960484Sobrien    protected DPrinter(Context context) {
14060484Sobrien        context.put(DPrinter.class, this);
14160484Sobrien        out = context.get(Log.logKey).getWriter(Log.WriterKind.STDERR);
14260484Sobrien        trees = JavacTrees.instance(context);
14360484Sobrien    }
14460484Sobrien
14533965Sjdp    public DPrinter(PrintWriter out, Trees trees) {
14633965Sjdp        this.out = out;
14733965Sjdp        this.trees = trees;
14833965Sjdp    }
14933965Sjdp
15033965Sjdp    public DPrinter emptyItems(boolean showEmptyItems) {
15133965Sjdp        this.showEmptyItems = showEmptyItems;
15233965Sjdp        return this;
15333965Sjdp    }
15433965Sjdp
15538889Sjdp    public DPrinter nulls(boolean showNulls) {
15638889Sjdp        this.showNulls = showNulls;
15738889Sjdp        return this;
15838889Sjdp    }
15933965Sjdp
160130561Sobrien    public DPrinter positions(boolean showPositions) {
161130561Sobrien        this.showPositions = showPositions;
162130561Sobrien        return this;
163130561Sobrien    }
164130561Sobrien
16577298Sobrien    public DPrinter source(boolean showSrc) {
16677298Sobrien        this.showSrc = showSrc;
16777298Sobrien        return this;
16877298Sobrien    }
16977298Sobrien
17060484Sobrien    public DPrinter source(int maxSrcLength) {
17160484Sobrien        this.showSrc = true;
17260484Sobrien        this.maxSrcLength = maxSrcLength;
17360484Sobrien        return this;
17460484Sobrien    }
17538889Sjdp
17660484Sobrien    public DPrinter treeSymbols(boolean showTreeSymbols) {
17760484Sobrien        this.showTreeSymbols = showTreeSymbols;
17860484Sobrien        return this;
17960484Sobrien    }
18060484Sobrien
18160484Sobrien    public DPrinter treeTypes(boolean showTreeTypes) {
18260484Sobrien        this.showTreeTypes = showTreeTypes;
18333965Sjdp        return this;
18433965Sjdp    }
18533965Sjdp
18633965Sjdp    public DPrinter typeSymbolPrinter(Printer p) {
18733965Sjdp        printer = p;
18833965Sjdp        return this;
18933965Sjdp    }
19033965Sjdp
19133965Sjdp    // </editor-fold>
19260484Sobrien
19333965Sjdp    // <editor-fold defaultstate="collapsed" desc="Printing">
19433965Sjdp
19533965Sjdp    protected enum Details {
19633965Sjdp        /** A one-line non-recursive summary */
19733965Sjdp        SUMMARY,
19891041Sobrien        /** Multi-line, possibly recursive. */
19933965Sjdp        FULL
20033965Sjdp    };
20133965Sjdp
20233965Sjdp    public void printAnnotations(String label, SymbolMetadata annotations) {
20333965Sjdp        printAnnotations(label, annotations, Details.FULL);
20433965Sjdp    }
20533965Sjdp
20633965Sjdp    protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
20733965Sjdp        if (annotations == null) {
20833965Sjdp            printNull(label);
20933965Sjdp        } else {
21033965Sjdp            // no SUMMARY format currently available to use
21133965Sjdp
21233965Sjdp            // use reflection to get at private fields
21333965Sjdp            Object DECL_NOT_STARTED = getField(null, SymbolMetadata.class, "DECL_NOT_STARTED");
21433965Sjdp            Object DECL_IN_PROGRESS = getField(null, SymbolMetadata.class, "DECL_IN_PROGRESS");
21533965Sjdp            Object attributes = getField(annotations, SymbolMetadata.class, "attributes");
21633965Sjdp            Object type_attributes = getField(annotations, SymbolMetadata.class, "type_attributes");
21733965Sjdp
21833965Sjdp            if (!showEmptyItems) {
21933965Sjdp                if (attributes instanceof List && ((List) attributes).isEmpty()
22033965Sjdp                        && attributes != DECL_NOT_STARTED
22133965Sjdp                        && attributes != DECL_IN_PROGRESS
22233965Sjdp                        && type_attributes instanceof List && ((List) type_attributes).isEmpty())
22333965Sjdp                    return;
22433965Sjdp            }
22533965Sjdp
22633965Sjdp            printString(label, hashString(annotations));
22733965Sjdp
22833965Sjdp            indent(+1);
22933965Sjdp            if (attributes == DECL_NOT_STARTED)
23033965Sjdp                printString("attributes", "DECL_NOT_STARTED");
23133965Sjdp            else if (attributes == DECL_IN_PROGRESS)
23291041Sobrien                printString("attributes", "DECL_IN_PROGRESS");
23333965Sjdp            else if (attributes instanceof List)
23433965Sjdp                printList("attributes", (List) attributes);
23533965Sjdp            else
23633965Sjdp                printObject("attributes", attributes, Details.SUMMARY);
23733965Sjdp
23833965Sjdp            if (attributes instanceof List)
23933965Sjdp                printList("type_attributes", (List) type_attributes);
24033965Sjdp            else
24133965Sjdp                printObject("type_attributes", type_attributes, Details.SUMMARY);
24233965Sjdp            indent(-1);
24333965Sjdp        }
24433965Sjdp    }
24560484Sobrien
24633965Sjdp    public void printAttribute(String label, Attribute attr) {
24733965Sjdp        if (attr == null) {
24833965Sjdp            printNull(label);
24933965Sjdp        } else {
25033965Sjdp            printString(label, attr.getClass().getSimpleName());
25133965Sjdp
252130561Sobrien            indent(+1);
253130561Sobrien            attr.accept(attrVisitor);
254130561Sobrien            indent(-1);
255130561Sobrien        }
256130561Sobrien    }
257130561Sobrien
25860484Sobrien    public void printDocTree(String label, DocTree tree) {
25960484Sobrien        if (tree == null) {
26060484Sobrien             printNull(label);
26160484Sobrien        } else {
26233965Sjdp            indent();
26333965Sjdp            out.print(label);
26433965Sjdp            out.println(": " + tree.getClass().getSimpleName() + "," + tree.getKind());
26533965Sjdp
26633965Sjdp            indent(+1);
26791041Sobrien            tree.accept(docTreeVisitor, null);
26860484Sobrien            indent(-1);
26960484Sobrien        }
27091041Sobrien    }
27133965Sjdp
27233965Sjdp    public void printFileObject(String label, FileObject fo) {
27377298Sobrien        if (fo == null) {
27433965Sjdp            printNull(label);
27533965Sjdp        } else {
27660484Sobrien            printString(label, fo.getName());
27760484Sobrien        }
27860484Sobrien    }
27960484Sobrien
28033965Sjdp    protected <T> void printImplClass(T item, Class<? extends T> stdImplClass) {
28191041Sobrien        if (item.getClass() != stdImplClass)
28291041Sobrien            printString("impl", item.getClass().getName());
28391041Sobrien    }
28433965Sjdp
28533965Sjdp    public void printInt(String label, int i) {
28633965Sjdp        printString(label, String.valueOf(i));
28733965Sjdp    }
28833965Sjdp
28933965Sjdp    public void printLimitedEscapedString(String label, String text) {
29033965Sjdp        String s = Convert.quote(text);
29133965Sjdp        if (s.length() > maxSrcLength) {
29233965Sjdp            String trim = "[...]";
29333965Sjdp            int head = (maxSrcLength - trim.length()) * 2 / 3;
29433965Sjdp            int tail = maxSrcLength - trim.length() - head;
29533965Sjdp            s = s.substring(0, head) + trim + s.substring(s.length() - tail);
29633965Sjdp        }
29733965Sjdp        printString(label, s);
29833965Sjdp    }
29933965Sjdp
30033965Sjdp    public void printList(String label, List<?> list) {
30133965Sjdp        if (list == null) {
30233965Sjdp             printNull(label);
30333965Sjdp        } else if (!list.isEmpty() || showEmptyItems) {
30433965Sjdp            printString(label, "[" + list.size() + "]");
30533965Sjdp
30633965Sjdp            indent(+1);
30791041Sobrien            int i = 0;
308104834Sobrien            for (Object item: list) {
30991041Sobrien                printObject(String.valueOf(i++), item, Details.FULL);
310104834Sobrien            }
31191041Sobrien            indent(-1);
31291041Sobrien        }
31391041Sobrien    }
31433965Sjdp
31577298Sobrien    public void printName(String label, Name name) {
31633965Sjdp        if (name == null) {
31733965Sjdp            printNull(label);
31833965Sjdp        } else {
31933965Sjdp            printString(label, name.toString());
32033965Sjdp        }
32177298Sobrien    }
32233965Sjdp
32333965Sjdp    public void printNull(String label) {
32433965Sjdp        if (showNulls)
32533965Sjdp            printString(label, NULL);
32633965Sjdp    }
32733965Sjdp
32833965Sjdp    protected void printObject(String label, Object item, Details details) {
32933965Sjdp        if (item == null) {
33033965Sjdp            printNull(label);
33133965Sjdp        } else if (item instanceof Attribute) {
33233965Sjdp            printAttribute(label, (Attribute) item);
33333965Sjdp        } else if (item instanceof Symbol) {
33433965Sjdp            printSymbol(label, (Symbol) item, details);
33577298Sobrien        } else if (item instanceof Type) {
33677298Sobrien            printType(label, (Type) item, details);
33733965Sjdp        } else if (item instanceof JCTree) {
33891041Sobrien            printTree(label, (JCTree) item);
33960484Sobrien        } else if (item instanceof DocTree) {
34060484Sobrien            printDocTree(label, (DocTree) item);
34160484Sobrien        } else if (item instanceof List) {
34233965Sjdp            printList(label, (List) item);
34333965Sjdp        } else if (item instanceof Name) {
34433965Sjdp            printName(label, (Name) item);
34533965Sjdp        } else if (item instanceof Scope) {
34633965Sjdp            printScope(label, (Scope) item);
34733965Sjdp        } else {
34833965Sjdp            printString(label, String.valueOf(item));
34933965Sjdp        }
35033965Sjdp    }
35133965Sjdp
35233965Sjdp    public void printScope(String label, Scope scope) {
35333965Sjdp        printScope(label, scope, Details.FULL);
35433965Sjdp    }
35533965Sjdp
35633965Sjdp    public void printScope(String label, Scope scope, Details details) {
35733965Sjdp        if (scope == null) {
35833965Sjdp            printNull(label);
35933965Sjdp        } else {
36091041Sobrien            switch (details) {
36133965Sjdp                case SUMMARY: {
36277298Sobrien                    indent();
36333965Sjdp                    out.print(label);
36433965Sjdp                    out.print(": [");
36533965Sjdp                    String sep = "";
36633965Sjdp                    for (Symbol sym: scope.getSymbols()) {
36733965Sjdp                        out.print(sep);
36833965Sjdp                        out.print(sym.name);
36933965Sjdp                        sep = ",";
37033965Sjdp                    }
37133965Sjdp                    out.println("]");
37233965Sjdp                    break;
37333965Sjdp                }
37433965Sjdp
37533965Sjdp                case FULL: {
37633965Sjdp                    indent();
37733965Sjdp                    out.println(label);
37833965Sjdp
37933965Sjdp                    indent(+1);
38033965Sjdp                    printFullScopeImpl(scope);
38133965Sjdp                    indent(-1);
38233965Sjdp                    break;
38333965Sjdp                }
38433965Sjdp            }
38533965Sjdp        }
38633965Sjdp    }
38760484Sobrien
38833965Sjdp    void printFullScopeImpl(Scope scope) {
38977298Sobrien        indent();
39033965Sjdp        out.println(scope.getClass().getName());
39133965Sjdp        printSymbol("owner", scope.owner, Details.SUMMARY);
39260484Sobrien        if (SCOPE_IMPL_CLASS.equals(scope.getClass().getName())) {
39333965Sjdp            printScope("next", (Scope) getField(scope, scope.getClass(), "next"), Details.SUMMARY);
39433965Sjdp            printObject("shared", getField(scope, scope.getClass(), "shared"), Details.SUMMARY);
39533965Sjdp            Object[] table = (Object[]) getField(scope, scope.getClass(), "table");
39638889Sjdp            for (int i = 0; i < table.length; i++) {
39733965Sjdp                if (i > 0)
39860484Sobrien                    out.print(", ");
39933965Sjdp                else
40060484Sobrien                    indent();
40133965Sjdp                out.print(i + ":" + entryToString(table[i], table, false));
40238889Sjdp            }
40333965Sjdp            out.println();
40460484Sobrien        } else if (FILTER_SCOPE_CLASS.equals(scope.getClass().getName())) {
40533965Sjdp            printScope("origin",
40633965Sjdp                    (Scope) getField(scope, scope.getClass(), "origin"), Details.FULL);
40733965Sjdp        } else if (scope instanceof CompoundScope) {
40860484Sobrien            printList("delegates", (List<?>) getField(scope, CompoundScope.class, "subScopes"));
40933965Sjdp        } else {
41033965Sjdp            for (Symbol sym : scope.getSymbols()) {
41133965Sjdp                printSymbol(sym.name.toString(), sym, Details.SUMMARY);
41233965Sjdp            }
41333965Sjdp        }
41433965Sjdp    }
41533965Sjdp        //where:
41633965Sjdp        static final String SCOPE_IMPL_CLASS = "com.sun.tools.javac.code.Scope$ScopeImpl";
41733965Sjdp        static final String FILTER_SCOPE_CLASS = "com.sun.tools.javac.code.Scope$FilterImportScope";
41833965Sjdp
41933965Sjdp    /**
42060484Sobrien     * Create a string showing the contents of an entry, using the table
42133965Sjdp     * to help identify cross-references to other entries in the table.
42291041Sobrien     * @param e the entry to be shown
42333965Sjdp     * @param table the table containing the other entries
42433965Sjdp     */
42533965Sjdp    String entryToString(Object e, Object[] table, boolean ref) {
42633965Sjdp        if (e == null)
42733965Sjdp            return "null";
42833965Sjdp        Symbol sym = (Symbol) getField(e, e.getClass(), "sym");
42933965Sjdp        if (sym == null)
43033965Sjdp            return "sent"; // sentinel
43133965Sjdp        if (ref) {
43291041Sobrien            int index = indexOf(table, e);
43391041Sobrien            if (index != -1)
43433965Sjdp                return String.valueOf(index);
43533965Sjdp        }
43633965Sjdp        Scope scope = (Scope) getField(e, e.getClass(), "scope");
43733965Sjdp        return "(" + sym.name + ":" + sym
43833965Sjdp                + ",shdw:" + entryToString(callMethod(e, e.getClass(), "next"), table, true)
43933965Sjdp                + ",sibl:" + entryToString(getField(e, e.getClass(), "sibling"), table, true)
44033965Sjdp                + ((sym.owner != scope.owner)
44133965Sjdp                    ? (",BOGUS[" + sym.owner + "," + scope.owner + "]")
44233965Sjdp                    : "")
44333965Sjdp                + ")";
44433965Sjdp    }
44533965Sjdp
44633965Sjdp    <T> int indexOf(T[] array, T item) {
44733965Sjdp        for (int i = 0; i < array.length; i++) {
44833965Sjdp            if (array[i] == item)
44933965Sjdp                return i;
45077298Sobrien        }
45133965Sjdp        return -1;
45233965Sjdp    }
45333965Sjdp
45433965Sjdp    public void printSource(String label, JCTree tree) {
45591041Sobrien        printString(label, Pretty.toSimpleString(tree, maxSrcLength));
45633965Sjdp    }
45733965Sjdp
45833965Sjdp    public void printString(String label, String text) {
45933965Sjdp        indent();
46033965Sjdp        out.print(label);
46177298Sobrien        out.print(": ");
46233965Sjdp        out.print(text);
46391041Sobrien        out.println();
46433965Sjdp    }
46533965Sjdp
46633965Sjdp    public void printSymbol(String label, Symbol symbol) {
46733965Sjdp        printSymbol(label, symbol, Details.FULL);
46833965Sjdp    }
46933965Sjdp
47091041Sobrien    protected void printSymbol(String label, Symbol sym, Details details) {
47133965Sjdp        if (sym == null) {
472130561Sobrien            printNull(label);
47391041Sobrien        } else {
47433965Sjdp            switch (details) {
47533965Sjdp            case SUMMARY:
47633965Sjdp                printString(label, toString(sym));
47733965Sjdp                break;
47833965Sjdp
47933965Sjdp            case FULL:
48033965Sjdp                indent();
48133965Sjdp                out.print(label);
48291041Sobrien                out.println(": " +
483130561Sobrien                        info(sym.getClass(),
48491041Sobrien                            String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
48533965Sjdp                            sym.getKind())
48691041Sobrien                        + " " + sym.name
48791041Sobrien                        + " " + hashString(sym));
488130561Sobrien
489130561Sobrien                indent(+1);
490130561Sobrien                if (showSrc) {
49133965Sjdp                    JCTree tree = (JCTree) trees.getTree(sym);
49233965Sjdp                    if (tree != null)
49391041Sobrien                        printSource("src", tree);
49433965Sjdp                }
49533965Sjdp                printString("flags", String.format("0x%x--%s",
49633965Sjdp                        sym.flags_field, Flags.toString(sym.flags_field)));
49733965Sjdp                printObject("completer", sym.completer, Details.SUMMARY); // what if too long?
49833965Sjdp                printSymbol("owner", sym.owner, Details.SUMMARY);
499130561Sobrien                printType("type", sym.type, Details.SUMMARY);
500130561Sobrien                printType("erasure", sym.erasure_field, Details.SUMMARY);
501130561Sobrien                sym.accept(symVisitor, null);
502130561Sobrien                printAnnotations("annotations", sym.getMetadata(), Details.SUMMARY);
503130561Sobrien                indent(-1);
504130561Sobrien            }
505130561Sobrien        }
50691041Sobrien    }
507130561Sobrien
508130561Sobrien    protected String toString(Symbol sym) {
509130561Sobrien        return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym);
51091041Sobrien    }
51191041Sobrien
51233965Sjdp    protected void printTree(String label, JCTree tree) {
51333965Sjdp        if (tree == null) {
51433965Sjdp            printNull(label);
51533965Sjdp        } else {
51638889Sjdp            indent();
51738889Sjdp            String ext;
51838889Sjdp            try {
51938889Sjdp                ext = tree.getKind().name();
520130561Sobrien            } catch (Throwable t) {
52191041Sobrien                ext = "n/a";
52233965Sjdp            }
52333965Sjdp            out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext));
524130561Sobrien            if (showPositions) {
52591041Sobrien                // We can always get start position, but to get end position
52691041Sobrien                // and/or line+offset, we would need a JCCompilationUnit
52733965Sjdp                out.print(" pos:" + tree.pos);
52833965Sjdp            }
529130561Sobrien            if (showTreeTypes && tree.type != null)
53077298Sobrien                out.print(" type:" + toString(tree.type));
53133965Sjdp            Symbol sym;
53233965Sjdp            if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null)
53360484Sobrien                out.print(" sym:" + toString(sym));
53460484Sobrien            out.println();
53560484Sobrien
53660484Sobrien            indent(+1);
53760484Sobrien            if (showSrc) {
53860484Sobrien                indent();
53960484Sobrien                out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength));
54060484Sobrien            }
54160484Sobrien            tree.accept(treeVisitor);
54260484Sobrien            indent(-1);
54391041Sobrien        }
54491041Sobrien    }
54577298Sobrien
546130561Sobrien    public void printType(String label, Type type) {
54791041Sobrien        printType(label, type, Details.FULL);
54833965Sjdp    }
549130561Sobrien
55091041Sobrien    protected void printType(String label, Type type, Details details) {
55133965Sjdp        if (type == null)
552130561Sobrien            printNull(label);
55391041Sobrien        else {
55433965Sjdp            switch (details) {
555130561Sobrien                case SUMMARY:
55691041Sobrien                    printString(label, toString(type));
55733965Sjdp                    break;
558130561Sobrien
55991041Sobrien                case FULL:
56033965Sjdp                    indent();
56133965Sjdp                    out.print(label);
56291041Sobrien                    out.println(": " + info(type.getClass(), type.getTag(), type.getKind())
56391041Sobrien                            + " " + hashString(type));
564130561Sobrien
565130561Sobrien                    indent(+1);
566130561Sobrien                    printSymbol("tsym", type.tsym, Details.SUMMARY);
56791041Sobrien                    printObject("constValue", type.constValue(), Details.SUMMARY);
568130561Sobrien                    printObject("annotations", type.getAnnotationMirrors(), Details.SUMMARY);
569130561Sobrien                    type.accept(typeVisitor, null);
570130561Sobrien                    indent(-1);
57191041Sobrien            }
572130561Sobrien        }
573130561Sobrien    }
574130561Sobrien
57591041Sobrien    protected String toString(Type type) {
576130561Sobrien        return (printer != null) ? printer.visit(type, locale) : String.valueOf(type);
577130561Sobrien    }
578130561Sobrien
57991041Sobrien    protected String hashString(Object obj) {
580130561Sobrien        return String.format("#%x", obj.hashCode());
581130561Sobrien    }
582130561Sobrien
58391041Sobrien    protected String info(Class<?> clazz, Object internal, Object external) {
584130561Sobrien        return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external);
585130561Sobrien    }
58633965Sjdp
58791041Sobrien    private int indent = 0;
58891041Sobrien
589130561Sobrien    protected void indent() {
590130561Sobrien        for (int i = 0; i < indent; i++) {
59133965Sjdp            out.print("  ");
59291041Sobrien        }
59391041Sobrien    }
59491041Sobrien
59533965Sjdp    protected void indent(int n) {
59633965Sjdp        indent += n;
59733965Sjdp    }
59833965Sjdp
59933965Sjdp    protected Object getField(Object o, Class<?> clazz, String name) {
60033965Sjdp        try {
60133965Sjdp            Field f = clazz.getDeclaredField(name);
60233965Sjdp            boolean prev = f.isAccessible();
60333965Sjdp            f.setAccessible(true);
60433965Sjdp            try {
60533965Sjdp                return f.get(o);
60633965Sjdp            } finally {
60733965Sjdp                f.setAccessible(prev);
60833965Sjdp            }
60933965Sjdp        } catch (ReflectiveOperationException e) {
61033965Sjdp            return e;
61191041Sobrien        } catch (SecurityException e) {
61233965Sjdp            return e;
61333965Sjdp        }
61433965Sjdp    }
61533965Sjdp
61633965Sjdp    protected Object callMethod(Object o, Class<?> clazz, String name) {
61733965Sjdp        try {
61833965Sjdp            Method m = clazz.getDeclaredMethod(name);
61933965Sjdp            boolean prev = m.isAccessible();
62033965Sjdp            m.setAccessible(true);
62133965Sjdp            try {
62233965Sjdp                return m.invoke(o);
62333965Sjdp            } finally {
62433965Sjdp                m.setAccessible(prev);
62533965Sjdp            }
62691041Sobrien        } catch (ReflectiveOperationException e) {
627104834Sobrien            return e;
62891041Sobrien        } catch (SecurityException e) {
629104834Sobrien            return e;
63091041Sobrien        }
63191041Sobrien    }
63291041Sobrien
63333965Sjdp    // </editor-fold>
63477298Sobrien
63533965Sjdp    // <editor-fold defaultstate="collapsed" desc="JCTree visitor methods">
63633965Sjdp
63733965Sjdp    protected JCTree.Visitor treeVisitor = new TreeVisitor();
63833965Sjdp
63933965Sjdp    /**
64077298Sobrien     * Default visitor class for JCTree (AST) objects.
64133965Sjdp     */
64233965Sjdp    public class TreeVisitor extends JCTree.Visitor {
64333965Sjdp        @Override
64433965Sjdp        public void visitTopLevel(JCCompilationUnit tree) {
64533965Sjdp            printList("packageAnnotations", tree.getPackageAnnotations());
64633965Sjdp            printList("defs", tree.defs);
64733965Sjdp        }
64833965Sjdp
64933965Sjdp        @Override
65033965Sjdp        public void visitPackageDef(JCPackageDecl tree) {
65133965Sjdp            printTree("pid", tree.pid);
65233965Sjdp        }
65333965Sjdp
65477298Sobrien        @Override
65533965Sjdp        public void visitImport(JCImport tree) {
65677298Sobrien            printTree("qualid", tree.qualid);
65733965Sjdp        }
65891041Sobrien
65933965Sjdp        @Override
66033965Sjdp        public void visitClassDef(JCClassDecl tree) {
66133965Sjdp            printName("name", tree.name);
66233965Sjdp            printTree("mods", tree.mods);
66333965Sjdp            printList("typarams", tree.typarams);
66433965Sjdp            printTree("extending", tree.extending);
66533965Sjdp            printList("implementing", tree.implementing);
66633965Sjdp            printList("defs", tree.defs);
66733965Sjdp        }
66833965Sjdp
66933965Sjdp        @Override
67033965Sjdp        public void visitMethodDef(JCMethodDecl tree) {
67133965Sjdp            printName("name", tree.name);
67233965Sjdp            printTree("mods", tree.mods);
67333965Sjdp            printTree("restype", tree.restype);
67433965Sjdp            printList("typarams", tree.typarams);
67533965Sjdp            printTree("recvparam", tree.recvparam);
67633965Sjdp            printList("params", tree.params);
67733965Sjdp            printList("thrown", tree.thrown);
67833965Sjdp            printTree("defaultValue", tree.defaultValue);
67933965Sjdp            printTree("body", tree.body);
68091041Sobrien        }
68133965Sjdp
68277298Sobrien        @Override
68333965Sjdp        public void visitVarDef(JCVariableDecl tree) {
68433965Sjdp            printName("name", tree.name);
68533965Sjdp            printTree("mods", tree.mods);
68633965Sjdp            printTree("vartype", tree.vartype);
68733965Sjdp            printTree("init", tree.init);
68833965Sjdp        }
68933965Sjdp
69033965Sjdp        @Override
69133965Sjdp        public void visitSkip(JCSkip tree) {
69233965Sjdp        }
69333965Sjdp
69433965Sjdp        @Override
69533965Sjdp        public void visitBlock(JCBlock tree) {
69633965Sjdp            printList("stats", tree.stats);
69733965Sjdp        }
69833965Sjdp
69933965Sjdp        @Override
70033965Sjdp        public void visitDoLoop(JCDoWhileLoop tree) {
70133965Sjdp            printTree("body", tree.body);
70233965Sjdp            printTree("cond", tree.cond);
70391041Sobrien        }
70433965Sjdp
70591041Sobrien        @Override
70691041Sobrien        public void visitWhileLoop(JCWhileLoop tree) {
70733965Sjdp            printTree("cond", tree.cond);
70833965Sjdp            printTree("body", tree.body);
70933965Sjdp        }
71033965Sjdp
71133965Sjdp        @Override
71233965Sjdp        public void visitForLoop(JCForLoop tree) {
71333965Sjdp            printList("init", tree.init);
71433965Sjdp            printTree("cond", tree.cond);
71577298Sobrien            printList("step", tree.step);
71633965Sjdp            printTree("body", tree.body);
71733965Sjdp        }
71833965Sjdp
71933965Sjdp        @Override
72033965Sjdp        public void visitForeachLoop(JCEnhancedForLoop tree) {
72133965Sjdp            printTree("var", tree.var);
72277298Sobrien            printTree("expr", tree.expr);
72333965Sjdp            printTree("body", tree.body);
72433965Sjdp        }
72577298Sobrien
72633965Sjdp        @Override
72733965Sjdp        public void visitLabelled(JCLabeledStatement tree) {
72833965Sjdp            printTree("body", tree.body);
72933965Sjdp        }
73077298Sobrien
73133965Sjdp        @Override
73233965Sjdp        public void visitSwitch(JCSwitch tree) {
73333965Sjdp            printTree("selector", tree.selector);
73477298Sobrien            printList("cases", tree.cases);
73533965Sjdp        }
73633965Sjdp
73733965Sjdp        @Override
73833965Sjdp        public void visitCase(JCCase tree) {
73977298Sobrien            printTree("pat", tree.pat);
74033965Sjdp            printList("stats", tree.stats);
74133965Sjdp        }
74233965Sjdp
74333965Sjdp        @Override
74491041Sobrien        public void visitSynchronized(JCSynchronized tree) {
74591041Sobrien            printTree("lock", tree.lock);
74633965Sjdp            printTree("body", tree.body);
74733965Sjdp        }
74833965Sjdp
74933965Sjdp        @Override
75033965Sjdp        public void visitTry(JCTry tree) {
75133965Sjdp            printList("resources", tree.resources);
75233965Sjdp            printTree("body", tree.body);
75333965Sjdp            printList("catchers", tree.catchers);
75491041Sobrien            printTree("finalizer", tree.finalizer);
75533965Sjdp        }
75633965Sjdp
75733965Sjdp        @Override
75833965Sjdp        public void visitCatch(JCCatch tree) {
75933965Sjdp            printTree("param", tree.param);
76033965Sjdp            printTree("body", tree.body);
76133965Sjdp        }
76233965Sjdp
76391041Sobrien        @Override
76433965Sjdp        public void visitConditional(JCConditional tree) {
76533965Sjdp            printTree("cond", tree.cond);
76633965Sjdp            printTree("truepart", tree.truepart);
76733965Sjdp            printTree("falsepart", tree.falsepart);
76833965Sjdp        }
76977298Sobrien
77077298Sobrien        @Override
77133965Sjdp        public void visitIf(JCIf tree) {
77233965Sjdp            printTree("cond", tree.cond);
77377298Sobrien            printTree("thenpart", tree.thenpart);
77433965Sjdp            printTree("elsepart", tree.elsepart);
77533965Sjdp        }
77633965Sjdp
77733965Sjdp        @Override
77833965Sjdp        public void visitExec(JCExpressionStatement tree) {
77933965Sjdp            printTree("expr", tree.expr);
78091041Sobrien        }
78191041Sobrien
78233965Sjdp        @Override
78333965Sjdp        public void visitBreak(JCBreak tree) {
78433965Sjdp            printName("label", tree.label);
78533965Sjdp        }
78633965Sjdp
78733965Sjdp        @Override
78833965Sjdp        public void visitContinue(JCContinue tree) {
78933965Sjdp            printName("label", tree.label);
79091041Sobrien        }
79133965Sjdp
79233965Sjdp        @Override
79333965Sjdp        public void visitReturn(JCReturn tree) {
79433965Sjdp            printTree("expr", tree.expr);
79533965Sjdp        }
79633965Sjdp
79733965Sjdp        @Override
798130561Sobrien        public void visitThrow(JCThrow tree) {
79933965Sjdp            printTree("expr", tree.expr);
80033965Sjdp        }
80133965Sjdp
80233965Sjdp        @Override
80391041Sobrien        public void visitAssert(JCAssert tree) {
80433965Sjdp            printTree("cond", tree.cond);
80533965Sjdp            printTree("detail", tree.detail);
80633965Sjdp        }
80733965Sjdp
80877298Sobrien        @Override
80991041Sobrien        public void visitApply(JCMethodInvocation tree) {
81091041Sobrien            printList("typeargs", tree.typeargs);
81191041Sobrien            printTree("meth", tree.meth);
81291041Sobrien            printList("args", tree.args);
81391041Sobrien        }
81491041Sobrien
81533965Sjdp        @Override
81633965Sjdp        public void visitNewClass(JCNewClass tree) {
81733965Sjdp            printTree("encl", tree.encl);
81833965Sjdp            printList("typeargs", tree.typeargs);
81933965Sjdp            printTree("clazz", tree.clazz);
82091041Sobrien            printList("args", tree.args);
82191041Sobrien            printTree("def", tree.def);
82233965Sjdp        }
82333965Sjdp
82433965Sjdp        @Override
82533965Sjdp        public void visitNewArray(JCNewArray tree) {
82633965Sjdp            printList("annotations", tree.annotations);
82733965Sjdp            printTree("elemtype", tree.elemtype);
82833965Sjdp            printList("dims", tree.dims);
82933965Sjdp            printList("dimAnnotations", tree.dimAnnotations);
83033965Sjdp            printList("elems", tree.elems);
83133965Sjdp        }
83233965Sjdp
83333965Sjdp        @Override
83433965Sjdp        public void visitLambda(JCLambda tree) {
83533965Sjdp            printTree("body", tree.body);
83660484Sobrien            printList("params", tree.params);
83733965Sjdp        }
83833965Sjdp
83933965Sjdp        @Override
84033965Sjdp        public void visitParens(JCParens tree) {
84133965Sjdp            printTree("expr", tree.expr);
84233965Sjdp        }
84333965Sjdp
84433965Sjdp        @Override
84533965Sjdp        public void visitAssign(JCAssign tree) {
84633965Sjdp            printTree("lhs", tree.lhs);
84733965Sjdp            printTree("rhs", tree.rhs);
84833965Sjdp        }
84933965Sjdp
85060484Sobrien        @Override
85133965Sjdp        public void visitAssignop(JCAssignOp tree) {
85233965Sjdp            printTree("lhs", tree.lhs);
85391041Sobrien            printTree("rhs", tree.rhs);
85433965Sjdp        }
85533965Sjdp
85633965Sjdp        @Override
85733965Sjdp        public void visitUnary(JCUnary tree) {
85833965Sjdp            printTree("arg", tree.arg);
85933965Sjdp        }
86033965Sjdp
86133965Sjdp        @Override
86233965Sjdp        public void visitBinary(JCBinary tree) {
86333965Sjdp            printTree("lhs", tree.lhs);
86433965Sjdp            printTree("rhs", tree.rhs);
86533965Sjdp        }
86633965Sjdp
86733965Sjdp        @Override
86833965Sjdp        public void visitTypeCast(JCTypeCast tree) {
86933965Sjdp            printTree("clazz", tree.clazz);
87033965Sjdp            printTree("expr", tree.expr);
87133965Sjdp        }
87233965Sjdp
87333965Sjdp        @Override
87433965Sjdp        public void visitTypeTest(JCInstanceOf tree) {
87533965Sjdp            printTree("expr", tree.expr);
87660484Sobrien            printTree("clazz", tree.clazz);
87760484Sobrien        }
87860484Sobrien
87960484Sobrien        @Override
88060484Sobrien        public void visitIndexed(JCArrayAccess tree) {
88160484Sobrien            printTree("indexed", tree.indexed);
88238889Sjdp            printTree("index", tree.index);
88338889Sjdp        }
88438889Sjdp
88538889Sjdp        @Override
88638889Sjdp        public void visitSelect(JCFieldAccess tree) {
88738889Sjdp            printTree("selected", tree.selected);
88838889Sjdp        }
88938889Sjdp
89038889Sjdp        @Override
89138889Sjdp        public void visitReference(JCMemberReference tree) {
89238889Sjdp            printTree("expr", tree.expr);
89338889Sjdp            printList("typeargs", tree.typeargs);
89433965Sjdp        }
89533965Sjdp
89633965Sjdp        @Override
89733965Sjdp        public void visitIdent(JCIdent tree) {
89833965Sjdp            printName("name", tree.name);
89933965Sjdp        }
90033965Sjdp
90133965Sjdp        @Override
90260484Sobrien        public void visitLiteral(JCLiteral tree) {
90360484Sobrien            printString("value", Pretty.toSimpleString(tree, 32));
90460484Sobrien        }
90560484Sobrien
90633965Sjdp        @Override
907        public void visitTypeIdent(JCPrimitiveTypeTree tree) {
908            printString("typetag", tree.typetag.name());
909        }
910
911        @Override
912        public void visitTypeArray(JCArrayTypeTree tree) {
913            printTree("elemtype", tree.elemtype);
914        }
915
916        @Override
917        public void visitTypeApply(JCTypeApply tree) {
918            printTree("clazz", tree.clazz);
919            printList("arguments", tree.arguments);
920        }
921
922        @Override
923        public void visitTypeUnion(JCTypeUnion tree) {
924            printList("alternatives", tree.alternatives);
925        }
926
927        @Override
928        public void visitTypeIntersection(JCTypeIntersection tree) {
929            printList("bounds", tree.bounds);
930        }
931
932        @Override
933        public void visitTypeParameter(JCTypeParameter tree) {
934            printName("name", tree.name);
935            printList("annotations", tree.annotations);
936            printList("bounds", tree.bounds);
937        }
938
939        @Override
940        public void visitWildcard(JCWildcard tree) {
941            printTree("kind", tree.kind);
942            printTree("inner", tree.inner);
943        }
944
945        @Override
946        public void visitTypeBoundKind(TypeBoundKind tree) {
947            printString("kind", tree.kind.name());
948        }
949
950        @Override
951        public void visitModifiers(JCModifiers tree) {
952            printList("annotations", tree.annotations);
953            printString("flags", String.valueOf(Flags.asFlagSet(tree.flags)));
954        }
955
956        @Override
957        public void visitAnnotation(JCAnnotation tree) {
958            printTree("annotationType", tree.annotationType);
959            printList("args", tree.args);
960        }
961
962        @Override
963        public void visitAnnotatedType(JCAnnotatedType tree) {
964            printList("annotations", tree.annotations);
965            printTree("underlyingType", tree.underlyingType);
966        }
967
968        @Override
969        public void visitErroneous(JCErroneous tree) {
970            printList("errs", tree.errs);
971        }
972
973        @Override
974        public void visitLetExpr(LetExpr tree) {
975            printList("defs", tree.defs);
976            printTree("expr", tree.expr);
977        }
978
979        @Override
980        public void visitTree(JCTree tree) {
981            Assert.error();
982        }
983    }
984
985    // </editor-fold>
986
987    // <editor-fold defaultstate="collapsed" desc="DocTree visitor">
988
989    protected DocTreeVisitor<Void,Void> docTreeVisitor = new DefaultDocTreeVisitor();
990
991    /**
992     * Default visitor class for DocTree objects.
993     * Note: each visitXYZ method ends by calling the corresponding
994     * visit method for its superclass.
995     */
996    class DefaultDocTreeVisitor implements DocTreeVisitor<Void,Void> {
997
998        public Void visitAttribute(AttributeTree node, Void p) {
999            printName("name", node.getName());
1000            printString("vkind", node.getValueKind().name());
1001            printList("value", node.getValue());
1002            return visitTree(node, null);
1003        }
1004
1005        public Void visitAuthor(AuthorTree node, Void p) {
1006            printList("name", node.getName());
1007            return visitBlockTag(node, null);
1008        }
1009
1010        public Void visitComment(CommentTree node, Void p) {
1011            printLimitedEscapedString("body", node.getBody());
1012            return visitTree(node, null);
1013        }
1014
1015        public Void visitDeprecated(DeprecatedTree node, Void p) {
1016            printList("body", node.getBody());
1017            return visitBlockTag(node, null);
1018        }
1019
1020        public Void visitDocComment(DocCommentTree node, Void p) {
1021            printList("firstSentence", node.getFirstSentence());
1022            printList("body", node.getBody());
1023            printList("tags", node.getBlockTags());
1024            return visitTree(node, null);
1025        }
1026
1027        public Void visitDocRoot(DocRootTree node, Void p) {
1028            return visitInlineTag(node, null);
1029        }
1030
1031        public Void visitEndElement(EndElementTree node, Void p) {
1032            printName("name", node.getName());
1033            return visitTree(node, null);
1034        }
1035
1036        public Void visitEntity(EntityTree node, Void p) {
1037            printName("name", node.getName());
1038            return visitTree(node, null);
1039        }
1040
1041        public Void visitErroneous(ErroneousTree node, Void p) {
1042            printLimitedEscapedString("body", node.getBody());
1043            printString("diag", node.getDiagnostic().getMessage(Locale.getDefault()));
1044            return visitTree(node, null);
1045        }
1046
1047        public Void visitHidden(HiddenTree node, Void p) {
1048            printList("body", node.getBody());
1049            return visitBlockTag(node, null);
1050        }
1051
1052        public Void visitIdentifier(IdentifierTree node, Void p) {
1053            printName("name", node.getName());
1054            return visitTree(node, null);
1055        }
1056
1057        public Void visitIndex(IndexTree node, Void p) {
1058            printString("kind", node.getKind().name());
1059            printDocTree("term", node.getSearchTerm());
1060            printList("desc", node.getDescription());
1061            return visitInlineTag(node, p);
1062        }
1063
1064        public Void visitInheritDoc(InheritDocTree node, Void p) {
1065            return visitInlineTag(node, null);
1066        }
1067
1068        public Void visitLink(LinkTree node, Void p) {
1069            printString("kind", node.getKind().name());
1070            printDocTree("ref", node.getReference());
1071            printList("list", node.getLabel());
1072            return visitInlineTag(node, null);
1073        }
1074
1075        public Void visitLiteral(LiteralTree node, Void p) {
1076            printString("kind", node.getKind().name());
1077            printDocTree("body", node.getBody());
1078            return visitInlineTag(node, null);
1079        }
1080
1081        public Void visitParam(ParamTree node, Void p) {
1082            printString("isTypeParameter", String.valueOf(node.isTypeParameter()));
1083            printString("kind", node.getKind().name());
1084            printList("desc", node.getDescription());
1085            return visitBlockTag(node, null);
1086        }
1087
1088        public Void visitProvides(ProvidesTree node, Void p) {
1089            printString("kind", node.getKind().name());
1090            printDocTree("serviceType", node.getServiceType());
1091            printList("description", node.getDescription());
1092            return visitBlockTag(node, null);
1093        }
1094
1095        public Void visitReference(ReferenceTree node, Void p) {
1096            printString("signature", node.getSignature());
1097            return visitTree(node, null);
1098        }
1099
1100        public Void visitReturn(ReturnTree node, Void p) {
1101            printList("desc", node.getDescription());
1102            return visitBlockTag(node, null);
1103        }
1104
1105        public Void visitSee(SeeTree node, Void p) {
1106            printList("ref", node.getReference());
1107            return visitBlockTag(node, null);
1108        }
1109
1110        public Void visitSerial(SerialTree node, Void p) {
1111            printList("desc", node.getDescription());
1112            return visitBlockTag(node, null);
1113        }
1114
1115        public Void visitSerialData(SerialDataTree node, Void p) {
1116            printList("desc", node.getDescription());
1117            return visitBlockTag(node, null);
1118        }
1119
1120        public Void visitSerialField(SerialFieldTree node, Void p) {
1121            printDocTree("name", node.getName());
1122            printDocTree("type", node.getType());
1123            printList("desc", node.getDescription());
1124            return visitBlockTag(node, null);
1125        }
1126
1127        public Void visitSince(SinceTree node, Void p) {
1128            printList("body", node.getBody());
1129            return visitBlockTag(node, null);
1130        }
1131
1132        public Void visitStartElement(StartElementTree node, Void p) {
1133            printName("name", node.getName());
1134            printList("attrs", node.getAttributes());
1135            printString("selfClosing", String.valueOf(node.isSelfClosing()));
1136            return visitBlockTag(node, null);
1137        }
1138
1139        public Void visitText(TextTree node, Void p) {
1140            printLimitedEscapedString("body", node.getBody());
1141            return visitTree(node, null);
1142        }
1143
1144        public Void visitThrows(ThrowsTree node, Void p) {
1145            printDocTree("name", node.getExceptionName());
1146            printList("desc", node.getDescription());
1147            return visitBlockTag(node, null);
1148        }
1149
1150        public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
1151            printString("name", node.getTagName());
1152            printList("content", node.getContent());
1153            return visitBlockTag(node, null);
1154        }
1155
1156        public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
1157            printString("name", node.getTagName());
1158            printList("content", node.getContent());
1159            return visitInlineTag(node, null);
1160        }
1161
1162        public Void visitUses(UsesTree node, Void p) {
1163            printString("kind", node.getKind().name());
1164            printDocTree("serviceType", node.getServiceType());
1165            printList("description", node.getDescription());
1166            return visitBlockTag(node, null);
1167        }
1168
1169        public Void visitValue(ValueTree node, Void p) {
1170            printDocTree("value", node.getReference());
1171            return visitInlineTag(node, null);
1172        }
1173
1174        public Void visitVersion(VersionTree node, Void p) {
1175            printList("body", node.getBody());
1176            return visitBlockTag(node, null);
1177        }
1178
1179        public Void visitOther(DocTree node, Void p) {
1180            return visitTree(node, null);
1181        }
1182
1183        public Void visitBlockTag(DocTree node, Void p) {
1184            return visitTree(node, null);
1185        }
1186
1187        public Void visitInlineTag(DocTree node, Void p) {
1188            return visitTree(node, null);
1189        }
1190
1191        public Void visitTree(DocTree node, Void p) {
1192            return null;
1193        }
1194    }
1195
1196    // </editor-fold>
1197
1198    // <editor-fold defaultstate="collapsed" desc="Symbol visitor">
1199
1200    protected Symbol.Visitor<Void,Void> symVisitor = new SymbolVisitor();
1201
1202    /**
1203     * Default visitor class for Symbol objects.
1204     * Note: each visitXYZ method ends by calling the corresponding
1205     * visit method for its superclass.
1206     */
1207    class SymbolVisitor implements Symbol.Visitor<Void,Void> {
1208        @Override
1209        public Void visitClassSymbol(ClassSymbol sym, Void ignore) {
1210            printName("fullname", sym.fullname);
1211            printName("flatname", sym.flatname);
1212            printScope("members", sym.members_field);
1213            printFileObject("sourcefile", sym.sourcefile);
1214            printFileObject("classfile", sym.classfile);
1215            // trans-local?
1216            // pool?
1217            return visitTypeSymbol(sym, null);
1218        }
1219
1220        @Override
1221        public Void visitMethodSymbol(MethodSymbol sym, Void ignore) {
1222            // code
1223            printList("params", sym.params);
1224            printList("savedParameterNames", sym.savedParameterNames);
1225            return visitSymbol(sym, null);
1226        }
1227
1228        @Override
1229        public Void visitPackageSymbol(PackageSymbol sym, Void ignore) {
1230            printName("fullname", sym.fullname);
1231            printScope("members", sym.members_field);
1232            printSymbol("package-info", sym.package_info, Details.SUMMARY);
1233            return visitTypeSymbol(sym, null);
1234        }
1235
1236        @Override
1237        public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) {
1238            printInt("opcode", sym.opcode);
1239            return visitMethodSymbol(sym, null);
1240        }
1241
1242        @Override
1243        public Void visitVarSymbol(VarSymbol sym, Void ignore) {
1244            printInt("pos", sym.pos);
1245            printInt("adm", sym.adr);
1246            // data is a private field, and the standard accessors may
1247            // mutate it as part of lazy evaluation. Therefore, use
1248            // reflection to get the raw data.
1249            printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY);
1250            return visitSymbol(sym, null);
1251        }
1252
1253        @Override
1254        public Void visitTypeSymbol(TypeSymbol sym, Void ignore) {
1255            return visitSymbol(sym, null);
1256        }
1257
1258        @Override
1259        public Void visitSymbol(Symbol sym, Void ignore) {
1260            return null;
1261        }
1262    }
1263
1264    // </editor-fold>
1265
1266    // <editor-fold defaultstate="collapsed" desc="Type visitor">
1267
1268    protected Type.Visitor<Void,Void> typeVisitor = new TypeVisitor();
1269
1270    /**
1271     * Default visitor class for Type objects.
1272     * Note: each visitXYZ method ends by calling the corresponding
1273     * visit method for its superclass.
1274     */
1275    public class TypeVisitor implements Type.Visitor<Void,Void> {
1276        public Void visitArrayType(ArrayType type, Void ignore) {
1277            printType("elemType", type.elemtype, Details.FULL);
1278            return visitType(type, null);
1279        }
1280
1281        public Void visitCapturedType(CapturedType type, Void ignore) {
1282            printType("wildcard", type.wildcard, Details.FULL);
1283            return visitTypeVar(type, null);
1284        }
1285
1286        public Void visitClassType(ClassType type, Void ignore) {
1287            printType("outer", type.getEnclosingType(), Details.SUMMARY);
1288            printList("typarams", type.typarams_field);
1289            printList("allparams", type.allparams_field);
1290            printType("supertype", type.supertype_field, Details.SUMMARY);
1291            printList("interfaces", type.interfaces_field);
1292            printList("allinterfaces", type.all_interfaces_field);
1293            return visitType(type, null);
1294        }
1295
1296        public Void visitErrorType(ErrorType type, Void ignore) {
1297            printType("originalType", type.getOriginalType(), Details.FULL);
1298            return visitClassType(type, null);
1299        }
1300
1301        public Void visitForAll(ForAll type, Void ignore) {
1302            printList("tvars", type.tvars);
1303            return visitDelegatedType(type);
1304        }
1305
1306        public Void visitMethodType(MethodType type, Void ignore) {
1307            printList("argtypes", type.argtypes);
1308            printType("restype", type.restype, Details.FULL);
1309            printList("thrown", type.thrown);
1310            printType("recvtype", type.recvtype, Details.FULL);
1311            return visitType(type, null);
1312        }
1313
1314        public Void visitModuleType(ModuleType type, Void ignore) {
1315            return visitType(type, null);
1316        }
1317
1318        public Void visitPackageType(PackageType type, Void ignore) {
1319            return visitType(type, null);
1320        }
1321
1322        public Void visitTypeVar(TypeVar type, Void ignore) {
1323            // For TypeVars (and not subtypes), the bound should always be
1324            // null or bot. So, only print the bound for subtypes of TypeVar,
1325            // or if the bound is (erroneously) not null or bot.
1326            if (!type.hasTag(TypeTag.TYPEVAR)
1327                    || !(type.bound == null || type.bound.hasTag(TypeTag.BOT))) {
1328                printType("bound", type.bound, Details.FULL);
1329            }
1330            printType("lower", type.lower, Details.FULL);
1331            return visitType(type, null);
1332        }
1333
1334        public Void visitUndetVar(UndetVar type, Void ignore) {
1335            for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
1336                printList("bounds." + ib, type.getBounds(ib));
1337            printInt("declaredCount", type.declaredCount);
1338            printType("inst", type.getInst(), Details.SUMMARY);
1339            return visitDelegatedType(type);
1340        }
1341
1342        public Void visitWildcardType(WildcardType type, Void ignore) {
1343            printType("type", type.type, Details.SUMMARY);
1344            printString("kind", type.kind.name());
1345            printType("bound", type.bound, Details.SUMMARY);
1346            return visitType(type, null);
1347        }
1348
1349        protected Void visitDelegatedType(DelegatedType type) {
1350            printType("qtype", type.qtype, Details.FULL);
1351            return visitType(type, null);
1352        }
1353
1354        public Void visitType(Type type, Void ignore) {
1355            return null;
1356        }
1357    }
1358
1359    // </editor-fold>
1360
1361    // <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
1362
1363    protected Attribute.Visitor attrVisitor = new AttributeVisitor();
1364
1365    /**
1366     * Default visitor class for Attribute (annotation) objects.
1367     */
1368    public class AttributeVisitor implements Attribute.Visitor {
1369
1370        public void visitConstant(Attribute.Constant a) {
1371            printObject("value", a.value, Details.SUMMARY);
1372            visitAttribute(a);
1373        }
1374
1375        public void visitClass(Attribute.Class a) {
1376            printObject("classType", a.classType, Details.SUMMARY);
1377            visitAttribute(a);
1378        }
1379
1380        public void visitCompound(Attribute.Compound a) {
1381            if (a instanceof Attribute.TypeCompound) {
1382                Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
1383                // consider a custom printer?
1384                printObject("position", ta.position, Details.SUMMARY);
1385            }
1386            printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
1387            printList("values", a.values);
1388            visitAttribute(a);
1389        }
1390
1391        public void visitArray(Attribute.Array a) {
1392            printList("values", Arrays.asList(a.values));
1393            visitAttribute(a);
1394        }
1395
1396        public void visitEnum(Attribute.Enum a) {
1397            printSymbol("value", a.value, Details.SUMMARY);
1398            visitAttribute(a);
1399        }
1400
1401        public void visitError(Attribute.Error a) {
1402            visitAttribute(a);
1403        }
1404
1405        public void visitAttribute(Attribute a) {
1406            printType("type", a.type, Details.SUMMARY);
1407        }
1408
1409    }
1410    // </editor-fold>
1411
1412    // <editor-fold defaultstate="collapsed" desc="Utility front end">
1413
1414    /**
1415     * Utility class to invoke DPrinter from the command line.
1416     */
1417    static class Main {
1418        public static void main(String... args) throws IOException {
1419            Main m = new Main();
1420            PrintWriter out = new PrintWriter(System.out);
1421            try {
1422                if (args.length == 0)
1423                    m.usage(out);
1424                else
1425                    m.run(out, args);
1426            } finally {
1427                out.flush();
1428            }
1429        }
1430
1431        void usage(PrintWriter out) {
1432            out.println("Usage:");
1433            out.println("  java " + Main.class.getName() + " mode [options] [javac-options]");
1434            out.print("where mode is one of: ");
1435            String sep = "";
1436            for (Handler h: getHandlers().values()) {
1437                out.print(sep);
1438                out.print(h.name);
1439                sep = ", ";
1440            }
1441            out.println();
1442            out.println("and where options include:");
1443            out.println("  -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1444            out.println("  -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1445            out.println("  -showPositions");
1446            out.println("  -showSource");
1447            out.println("  -showTreeSymbols");
1448            out.println("  -showTreeTypes");
1449            out.println("  -hideEmptyItems");
1450            out.println("  -hideNulls");
1451        }
1452
1453        void run(PrintWriter out, String... args) throws IOException {
1454            JavaCompiler c = ToolProvider.getSystemJavaCompiler();
1455            StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
1456
1457            // DPrinter options
1458            final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
1459            final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
1460            boolean showPositions = false;
1461            boolean showSource = false;
1462            boolean showTreeSymbols = false;
1463            boolean showTreeTypes = false;
1464            boolean showEmptyItems = true;
1465            boolean showNulls = true;
1466
1467            // javac options
1468            Collection<String> options = new ArrayList<String>();
1469            Collection<File> files = new ArrayList<File>();
1470            String classpath = null;
1471            String classoutdir = null;
1472
1473            final Handler h = getHandlers().get(args[0]);
1474            if (h == null)
1475                throw new IllegalArgumentException(args[0]);
1476
1477            for (int i = 1; i < args.length; i++) {
1478                String arg = args[i];
1479                if (arg.equals("-before") && i + 1 < args.length) {
1480                    before.add(getKind(args[++i]));
1481                } else if (arg.equals("-after") && i + 1 < args.length) {
1482                    after.add(getKind(args[++i]));
1483                } else if (arg.equals("-showPositions")) {
1484                    showPositions = true;
1485                } else if (arg.equals("-showSource")) {
1486                    showSource = true;
1487                } else if (arg.equals("-showTreeSymbols")) {
1488                    showTreeSymbols = true;
1489                } else if (arg.equals("-showTreeTypes")) {
1490                    showTreeTypes = true;
1491                } else if (arg.equals("-hideEmptyLists")) {
1492                    showEmptyItems = false;
1493                } else if (arg.equals("-hideNulls")) {
1494                    showNulls = false;
1495                } else if (arg.equals("-classpath") && i + 1 < args.length) {
1496                    classpath = args[++i];
1497                } else if (arg.equals("-d") && i + 1 < args.length) {
1498                    classoutdir = args[++i];
1499                } else if (arg.startsWith("-")) {
1500                    int n = c.isSupportedOption(arg);
1501                    if (n < 0) throw new IllegalArgumentException(arg);
1502                    options.add(arg);
1503                    while (n > 0) options.add(args[++i]);
1504                } else if (arg.endsWith(".java")) {
1505                    files.add(new File(arg));
1506                }
1507            }
1508
1509            if (classoutdir != null) {
1510                fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
1511            }
1512
1513            if (classpath != null) {
1514                Collection<File> path = new ArrayList<File>();
1515                for (String p: classpath.split(File.pathSeparator)) {
1516                    if (p.isEmpty()) continue;
1517                    File f = new File(p);
1518                    if (f.exists()) path.add(f);
1519                }
1520                fm.setLocation(StandardLocation.CLASS_PATH, path);
1521            }
1522            Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
1523
1524            JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
1525            final Trees trees = Trees.instance(task);
1526
1527            final DPrinter dprinter = new DPrinter(out, trees);
1528            dprinter.source(showSource)
1529                    .emptyItems(showEmptyItems)
1530                    .nulls(showNulls)
1531                    .positions(showPositions)
1532                    .treeSymbols(showTreeSymbols)
1533                    .treeTypes(showTreeTypes);
1534
1535            if (before.isEmpty() && after.isEmpty()) {
1536                if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
1537                    after.add(TaskEvent.Kind.PARSE);
1538                else
1539                    after.add(TaskEvent.Kind.ANALYZE);
1540            }
1541
1542            task.addTaskListener(new TaskListener() {
1543                public void started(TaskEvent e) {
1544                    if (before.contains(e.getKind()))
1545                        handle(e);
1546                }
1547
1548                public void finished(TaskEvent e) {
1549                    if (after.contains(e.getKind()))
1550                        handle(e);
1551                }
1552
1553                private void handle(TaskEvent e) {
1554                    JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
1555                     switch (e.getKind()) {
1556                         case PARSE:
1557                         case ENTER:
1558                             h.handle(e.getSourceFile().getName(),
1559                                     unit, unit,
1560                                     dprinter);
1561                             break;
1562
1563                         default:
1564                             TypeElement elem = e.getTypeElement();
1565                             h.handle(elem.toString(),
1566                                     unit, (JCTree) trees.getTree(elem),
1567                                     dprinter);
1568                             break;
1569                     }
1570                }
1571            });
1572
1573            task.call();
1574        }
1575
1576        TaskEvent.Kind getKind(String s) {
1577            return TaskEvent.Kind.valueOf(s.toUpperCase());
1578        }
1579
1580        static protected abstract class Handler {
1581            final String name;
1582            Handler(String name) {
1583                this.name = name;
1584            }
1585            abstract void handle(String label,
1586                    JCCompilationUnit unit, JCTree tree,
1587                    DPrinter dprinter);
1588        }
1589
1590        Map<String,Handler> getHandlers() {
1591            Map<String,Handler> map = new HashMap<String, Handler>();
1592            for (Handler h: defaultHandlers) {
1593                map.put(h.name, h);
1594            }
1595            return map;
1596        }
1597
1598        protected final Handler[] defaultHandlers = {
1599            new Handler("trees") {
1600                @Override
1601                void handle(String name, JCCompilationUnit unit, JCTree tree, DPrinter dprinter) {
1602                    dprinter.printTree(name, tree);
1603                    dprinter.out.println();
1604                }
1605            },
1606
1607            new Handler("doctrees") {
1608                @Override
1609                void handle(final String name, final JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1610                    TreeScanner ds = new DeclScanner() {
1611                        public void visitDecl(JCTree tree, Symbol sym) {
1612                            DocTree dt = unit.docComments.getCommentTree(tree);
1613                            if (dt != null) {
1614                                String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1615                                dprinter.printDocTree(label, dt);
1616                                dprinter.out.println();
1617                            }
1618                        }
1619                    };
1620                    ds.scan(tree);
1621                }
1622            },
1623
1624            new Handler("symbols") {
1625                @Override
1626                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1627                    TreeScanner ds = new DeclScanner() {
1628                        public void visitDecl(JCTree tree, Symbol sym) {
1629                            String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1630                            dprinter.printSymbol(label, sym);
1631                            dprinter.out.println();
1632                        }
1633                    };
1634                    ds.scan(tree);
1635                }
1636            },
1637
1638            new Handler("types") {
1639                @Override
1640                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1641                    TreeScanner ts = new TreeScanner() {
1642                        @Override
1643                        public void scan(JCTree tree) {
1644                            if (tree == null) {
1645                                return;
1646                            }
1647                            if (tree.type != null) {
1648                                String label = Pretty.toSimpleString(tree);
1649                                dprinter.printType(label, tree.type);
1650                                dprinter.out.println();
1651                            }
1652                            super.scan(tree);
1653                        }
1654                    };
1655                    ts.scan(tree);
1656                }
1657            }
1658        };
1659    }
1660
1661    protected static abstract class DeclScanner extends TreeScanner {
1662        @Override
1663        public void visitClassDef(JCClassDecl tree) {
1664            visitDecl(tree, tree.sym);
1665            super.visitClassDef(tree);
1666        }
1667
1668        @Override
1669        public void visitMethodDef(JCMethodDecl tree) {
1670            visitDecl(tree, tree.sym);
1671            super.visitMethodDef(tree);
1672        }
1673
1674        @Override
1675        public void visitVarDef(JCVariableDecl tree) {
1676            visitDecl(tree, tree.sym);
1677            super.visitVarDef(tree);
1678        }
1679
1680        protected abstract void visitDecl(JCTree tree, Symbol sym);
1681    }
1682
1683    // </editor-fold>
1684
1685}
1686