DPrinter.java revision 3294:9adfb22ff08f
1230557Sjimharris/*
2230557Sjimharris * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
3230557Sjimharris * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4230557Sjimharris *
5230557Sjimharris * This code is free software; you can redistribute it and/or modify it
6230557Sjimharris * under the terms of the GNU General Public License version 2 only, as
7230557Sjimharris * published by the Free Software Foundation.
8230557Sjimharris *
9230557Sjimharris * This code is distributed in the hope that it will be useful, but WITHOUT
10230557Sjimharris * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11230557Sjimharris * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12230557Sjimharris * version 2 for more details (a copy is included in the LICENSE file that
13230557Sjimharris * accompanied this code).
14230557Sjimharris *
15230557Sjimharris * You should have received a copy of the GNU General Public License version
16230557Sjimharris * 2 along with this work; if not, write to the Free Software Foundation,
17230557Sjimharris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18230557Sjimharris *
19230557Sjimharris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20230557Sjimharris * or visit www.oracle.com if you need additional information or have any
21230557Sjimharris * questions.
22230557Sjimharris */
23230557Sjimharris
24230557Sjimharris/* @test
25230557Sjimharris * @bug 8043484 8007307
26230557Sjimharris * @summary Make sure DPrinter.java compiles
27230557Sjimharris * @modules jdk.compiler/com.sun.tools.javac.api
28230557Sjimharris *          jdk.compiler/com.sun.tools.javac.code
29230557Sjimharris *          jdk.compiler/com.sun.tools.javac.tree
30230557Sjimharris *          jdk.compiler/com.sun.tools.javac.util
31230557Sjimharris * @compile DPrinter.java
32230557Sjimharris */
33230557Sjimharris
34230557Sjimharrisimport java.io.File;
35230557Sjimharrisimport java.io.IOException;
36230557Sjimharrisimport java.io.PrintWriter;
37230557Sjimharrisimport java.lang.reflect.Field;
38230557Sjimharrisimport java.lang.reflect.Method;
39230557Sjimharrisimport java.util.ArrayList;
40230557Sjimharrisimport java.util.Arrays;
41230557Sjimharrisimport java.util.Collection;
42230557Sjimharrisimport java.util.EnumSet;
43230557Sjimharrisimport java.util.HashMap;
44230557Sjimharrisimport java.util.List;
45230557Sjimharrisimport java.util.Locale;
46230557Sjimharrisimport java.util.Map;
47230557Sjimharrisimport java.util.Set;
48230557Sjimharris
49230557Sjimharrisimport javax.lang.model.element.Name;
50230557Sjimharrisimport javax.lang.model.element.TypeElement;
51230557Sjimharrisimport javax.tools.FileObject;
52230557Sjimharrisimport javax.tools.JavaCompiler;
53230557Sjimharrisimport javax.tools.JavaFileObject;
54230557Sjimharrisimport javax.tools.StandardJavaFileManager;
55230557Sjimharrisimport javax.tools.StandardLocation;
56230557Sjimharrisimport javax.tools.ToolProvider;
57230557Sjimharris
58230557Sjimharrisimport com.sun.source.doctree.*;
59230557Sjimharrisimport com.sun.source.util.JavacTask;
60230557Sjimharrisimport com.sun.source.util.TaskEvent;
61230557Sjimharrisimport com.sun.source.util.TaskListener;
62230557Sjimharrisimport com.sun.source.util.Trees;
63230557Sjimharrisimport com.sun.tools.javac.api.JavacTrees;
64230557Sjimharrisimport com.sun.tools.javac.code.SymbolMetadata;
65230557Sjimharrisimport com.sun.tools.javac.code.Attribute;
66230557Sjimharrisimport com.sun.tools.javac.code.Flags;
67230557Sjimharrisimport com.sun.tools.javac.code.Kinds;
68230557Sjimharrisimport com.sun.tools.javac.code.Printer;
69230557Sjimharrisimport com.sun.tools.javac.code.Scope;
70230557Sjimharrisimport com.sun.tools.javac.code.Scope.CompoundScope;
71230557Sjimharrisimport com.sun.tools.javac.code.Symbol;
72230557Sjimharrisimport com.sun.tools.javac.code.Symbol.*;
73230557Sjimharrisimport com.sun.tools.javac.code.Type;
74230557Sjimharrisimport com.sun.tools.javac.code.Type.*;
75230557Sjimharrisimport com.sun.tools.javac.code.TypeTag;
76230557Sjimharrisimport com.sun.tools.javac.tree.JCTree;
77230557Sjimharrisimport com.sun.tools.javac.tree.JCTree.*;
78230557Sjimharrisimport com.sun.tools.javac.tree.Pretty;
79230557Sjimharrisimport com.sun.tools.javac.tree.TreeInfo;
80230557Sjimharrisimport com.sun.tools.javac.tree.TreeScanner;
81230557Sjimharrisimport com.sun.tools.javac.util.Assert;
82230557Sjimharrisimport com.sun.tools.javac.util.Context;
83230557Sjimharrisimport com.sun.tools.javac.util.Convert;
84230557Sjimharrisimport com.sun.tools.javac.util.Log;
85230557Sjimharris
86230557Sjimharris
87230557Sjimharris/**
88230557Sjimharris * Debug printer for javac internals, for when toString() just isn't enough.
89230557Sjimharris *
90230557Sjimharris * <p>
91230557Sjimharris * The printer provides an API to generate structured views of javac objects,
92230557Sjimharris * such as AST nodes, symbol, types and annotations. Various aspects of the
93230557Sjimharris * output can be configured, such as whether to show nulls, empty lists, or
94230557Sjimharris * a compressed representation of the source code. Visitors are used to walk
95230557Sjimharris * object hierarchies, and can be replaced with custom visitors if the default
96230557Sjimharris * visitors are not flexible enough.
97230557Sjimharris *
98230557Sjimharris * <p>
99230557Sjimharris * In general, nodes are printed with an initial line identifying the node
100230557Sjimharris * followed by indented lines for the child nodes. Currently, graphs are
101230557Sjimharris * represented by printing a spanning subtree.
102230557Sjimharris *
103230557Sjimharris * <p>
104230557Sjimharris * The printer can be accessed via a simple command-line utility,
105230557Sjimharris * which makes it easy to see the internal representation of source code,
106230557Sjimharris * such as simple test programs, during the compilation pipeline.
107230557Sjimharris *
108230557Sjimharris *  <p><b>This is NOT part of any supported API.
109230557Sjimharris *  If you write code that depends on this, you do so at your own risk.
110230557Sjimharris *  This code and its internal interfaces are subject to change or
111230557Sjimharris *  deletion without notice.</b>
112230557Sjimharris */
113230557Sjimharris
114230557Sjimharrispublic class DPrinter {
115230557Sjimharris    protected final PrintWriter out;
116230557Sjimharris    protected final Trees trees;
117230557Sjimharris    protected Printer printer;
118230557Sjimharris    protected boolean showEmptyItems = true;
119230557Sjimharris    protected boolean showNulls = true;
120230557Sjimharris    protected boolean showPositions = false;
121230557Sjimharris    protected boolean showSrc;
122230557Sjimharris    protected boolean showTreeSymbols;
123230557Sjimharris    protected boolean showTreeTypes;
124230557Sjimharris    protected int maxSrcLength = 32;
125230557Sjimharris    protected Locale locale = Locale.getDefault();
126230557Sjimharris    protected static final String NULL = "#null";
127230557Sjimharris
128230557Sjimharris    // <editor-fold defaultstate="collapsed" desc="Configuration">
129230557Sjimharris
130230557Sjimharris    public static DPrinter instance(Context context) {
131230557Sjimharris        DPrinter dp = context.get(DPrinter.class);
132230557Sjimharris        if (dp == null) {
133230557Sjimharris            dp = new DPrinter(context);
134230557Sjimharris        }
135230557Sjimharris        return dp;
136230557Sjimharris
137230557Sjimharris    }
138230557Sjimharris
139230557Sjimharris    protected DPrinter(Context context) {
140230557Sjimharris        context.put(DPrinter.class, this);
141230557Sjimharris        out = context.get(Log.outKey);
142230557Sjimharris        trees = JavacTrees.instance(context);
143230557Sjimharris    }
144230557Sjimharris
145230557Sjimharris    public DPrinter(PrintWriter out, Trees trees) {
146230557Sjimharris        this.out = out;
147230557Sjimharris        this.trees = trees;
148230557Sjimharris    }
149230557Sjimharris
150230557Sjimharris    public DPrinter emptyItems(boolean showEmptyItems) {
151230557Sjimharris        this.showEmptyItems = showEmptyItems;
152230557Sjimharris        return this;
153230557Sjimharris    }
154230557Sjimharris
155230557Sjimharris    public DPrinter nulls(boolean showNulls) {
156230557Sjimharris        this.showNulls = showNulls;
157230557Sjimharris        return this;
158230557Sjimharris    }
159230557Sjimharris
160230557Sjimharris    public DPrinter positions(boolean showPositions) {
161230557Sjimharris        this.showPositions = showPositions;
162230557Sjimharris        return this;
163230557Sjimharris    }
164230557Sjimharris
165230557Sjimharris    public DPrinter source(boolean showSrc) {
166230557Sjimharris        this.showSrc = showSrc;
167230557Sjimharris        return this;
168230557Sjimharris    }
169230557Sjimharris
170230557Sjimharris    public DPrinter source(int maxSrcLength) {
171230557Sjimharris        this.showSrc = true;
172230557Sjimharris        this.maxSrcLength = maxSrcLength;
173230557Sjimharris        return this;
174230557Sjimharris    }
175230557Sjimharris
176230557Sjimharris    public DPrinter treeSymbols(boolean showTreeSymbols) {
177230557Sjimharris        this.showTreeSymbols = showTreeSymbols;
178230557Sjimharris        return this;
179230557Sjimharris    }
180230557Sjimharris
181230557Sjimharris    public DPrinter treeTypes(boolean showTreeTypes) {
182230557Sjimharris        this.showTreeTypes = showTreeTypes;
183230557Sjimharris        return this;
184230557Sjimharris    }
185230557Sjimharris
186230557Sjimharris    public DPrinter typeSymbolPrinter(Printer p) {
187230557Sjimharris        printer = p;
188230557Sjimharris        return this;
189230557Sjimharris    }
190230557Sjimharris
191230557Sjimharris    // </editor-fold>
192230557Sjimharris
193230557Sjimharris    // <editor-fold defaultstate="collapsed" desc="Printing">
194230557Sjimharris
195230557Sjimharris    protected enum Details {
196230557Sjimharris        /** A one-line non-recursive summary */
197230557Sjimharris        SUMMARY,
198230557Sjimharris        /** Multi-line, possibly recursive. */
199230557Sjimharris        FULL
200230557Sjimharris    };
201230557Sjimharris
202230557Sjimharris    public void printAnnotations(String label, SymbolMetadata annotations) {
203230557Sjimharris        printAnnotations(label, annotations, Details.FULL);
204230557Sjimharris    }
205230557Sjimharris
206230557Sjimharris    protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
207230557Sjimharris        if (annotations == null) {
208230557Sjimharris            printNull(label);
209230557Sjimharris        } else {
210230557Sjimharris            // no SUMMARY format currently available to use
211230557Sjimharris
212230557Sjimharris            // use reflection to get at private fields
213230557Sjimharris            Object DECL_NOT_STARTED = getField(null, SymbolMetadata.class, "DECL_NOT_STARTED");
214230557Sjimharris            Object DECL_IN_PROGRESS = getField(null, SymbolMetadata.class, "DECL_IN_PROGRESS");
215230557Sjimharris            Object attributes = getField(annotations, SymbolMetadata.class, "attributes");
216230557Sjimharris            Object type_attributes = getField(annotations, SymbolMetadata.class, "type_attributes");
217230557Sjimharris
218230557Sjimharris            if (!showEmptyItems) {
219230557Sjimharris                if (attributes instanceof List && ((List) attributes).isEmpty()
220230557Sjimharris                        && attributes != DECL_NOT_STARTED
221230557Sjimharris                        && attributes != DECL_IN_PROGRESS
222230557Sjimharris                        && type_attributes instanceof List && ((List) type_attributes).isEmpty())
223230557Sjimharris                    return;
224230557Sjimharris            }
225230557Sjimharris
226230557Sjimharris            printString(label, hashString(annotations));
227230557Sjimharris
228230557Sjimharris            indent(+1);
229230557Sjimharris            if (attributes == DECL_NOT_STARTED)
230230557Sjimharris                printString("attributes", "DECL_NOT_STARTED");
231230557Sjimharris            else if (attributes == DECL_IN_PROGRESS)
232230557Sjimharris                printString("attributes", "DECL_IN_PROGRESS");
233230557Sjimharris            else if (attributes instanceof List)
234230557Sjimharris                printList("attributes", (List) attributes);
235230557Sjimharris            else
236230557Sjimharris                printObject("attributes", attributes, Details.SUMMARY);
237230557Sjimharris
238230557Sjimharris            if (attributes instanceof List)
239230557Sjimharris                printList("type_attributes", (List) type_attributes);
240230557Sjimharris            else
241230557Sjimharris                printObject("type_attributes", type_attributes, Details.SUMMARY);
242230557Sjimharris            indent(-1);
243230557Sjimharris        }
244230557Sjimharris    }
245230557Sjimharris
246230557Sjimharris    public void printAttribute(String label, Attribute attr) {
247230557Sjimharris        if (attr == null) {
248230557Sjimharris            printNull(label);
249230557Sjimharris        } else {
250230557Sjimharris            printString(label, attr.getClass().getSimpleName());
251230557Sjimharris
252230557Sjimharris            indent(+1);
253230557Sjimharris            attr.accept(attrVisitor);
254230557Sjimharris            indent(-1);
255230557Sjimharris        }
256230557Sjimharris    }
257230557Sjimharris
258230557Sjimharris    public void printDocTree(String label, DocTree tree) {
259230557Sjimharris        if (tree == null) {
260230557Sjimharris             printNull(label);
261230557Sjimharris        } else {
262230557Sjimharris            indent();
263230557Sjimharris            out.print(label);
264230557Sjimharris            out.println(": " + tree.getClass().getSimpleName() + "," + tree.getKind());
265230557Sjimharris
266230557Sjimharris            indent(+1);
267230557Sjimharris            tree.accept(docTreeVisitor, null);
268230557Sjimharris            indent(-1);
269230557Sjimharris        }
270230557Sjimharris    }
271230557Sjimharris
272230557Sjimharris    public void printFileObject(String label, FileObject fo) {
273230557Sjimharris        if (fo == null) {
274230557Sjimharris            printNull(label);
275230557Sjimharris        } else {
276230557Sjimharris            printString(label, fo.getName());
277230557Sjimharris        }
278230557Sjimharris    }
279230557Sjimharris
280230557Sjimharris    protected <T> void printImplClass(T item, Class<? extends T> stdImplClass) {
281230557Sjimharris        if (item.getClass() != stdImplClass)
282230557Sjimharris            printString("impl", item.getClass().getName());
283230557Sjimharris    }
284230557Sjimharris
285230557Sjimharris    public void printInt(String label, int i) {
286230557Sjimharris        printString(label, String.valueOf(i));
287230557Sjimharris    }
288230557Sjimharris
289230557Sjimharris    public void printLimitedEscapedString(String label, String text) {
290230557Sjimharris        String s = Convert.quote(text);
291230557Sjimharris        if (s.length() > maxSrcLength) {
292230557Sjimharris            String trim = "[...]";
293230557Sjimharris            int head = (maxSrcLength - trim.length()) * 2 / 3;
294230557Sjimharris            int tail = maxSrcLength - trim.length() - head;
295230557Sjimharris            s = s.substring(0, head) + trim + s.substring(s.length() - tail);
296230557Sjimharris        }
297230557Sjimharris        printString(label, s);
298230557Sjimharris    }
299230557Sjimharris
300230557Sjimharris    public void printList(String label, List<?> list) {
301230557Sjimharris        if (list == null) {
302230557Sjimharris             printNull(label);
303230557Sjimharris        } else if (!list.isEmpty() || showEmptyItems) {
304230557Sjimharris            printString(label, "[" + list.size() + "]");
305230557Sjimharris
306230557Sjimharris            indent(+1);
307230557Sjimharris            int i = 0;
308230557Sjimharris            for (Object item: list) {
309230557Sjimharris                printObject(String.valueOf(i++), item, Details.FULL);
310230557Sjimharris            }
311230557Sjimharris            indent(-1);
312230557Sjimharris        }
313230557Sjimharris    }
314230557Sjimharris
315230557Sjimharris    public void printName(String label, Name name) {
316230557Sjimharris        if (name == null) {
317230557Sjimharris            printNull(label);
318230557Sjimharris        } else {
319230557Sjimharris            printString(label, name.toString());
320230557Sjimharris        }
321230557Sjimharris    }
322230557Sjimharris
323230557Sjimharris    public void printNull(String label) {
324230557Sjimharris        if (showNulls)
325230557Sjimharris            printString(label, NULL);
326230557Sjimharris    }
327230557Sjimharris
328230557Sjimharris    protected void printObject(String label, Object item, Details details) {
329230557Sjimharris        if (item == null) {
330230557Sjimharris            printNull(label);
331230557Sjimharris        } else if (item instanceof Attribute) {
332230557Sjimharris            printAttribute(label, (Attribute) item);
333230557Sjimharris        } else if (item instanceof Symbol) {
334230557Sjimharris            printSymbol(label, (Symbol) item, details);
335230557Sjimharris        } else if (item instanceof Type) {
336230557Sjimharris            printType(label, (Type) item, details);
337230557Sjimharris        } else if (item instanceof JCTree) {
338230557Sjimharris            printTree(label, (JCTree) item);
339230557Sjimharris        } else if (item instanceof DocTree) {
340230557Sjimharris            printDocTree(label, (DocTree) item);
341230557Sjimharris        } else if (item instanceof List) {
342230557Sjimharris            printList(label, (List) item);
343230557Sjimharris        } else if (item instanceof Name) {
344230557Sjimharris            printName(label, (Name) item);
345230557Sjimharris        } else if (item instanceof Scope) {
346230557Sjimharris            printScope(label, (Scope) item);
347230557Sjimharris        } else {
348230557Sjimharris            printString(label, String.valueOf(item));
349230557Sjimharris        }
350230557Sjimharris    }
351230557Sjimharris
352230557Sjimharris    public void printScope(String label, Scope scope) {
353230557Sjimharris        printScope(label, scope, Details.FULL);
354230557Sjimharris    }
355230557Sjimharris
356230557Sjimharris    public void printScope(String label, Scope scope, Details details) {
357230557Sjimharris        if (scope == null) {
358230557Sjimharris            printNull(label);
359230557Sjimharris        } else {
360230557Sjimharris            switch (details) {
361230557Sjimharris                case SUMMARY: {
362235043Sjimharris                    indent();
363230557Sjimharris                    out.print(label);
364230557Sjimharris                    out.print(": [");
365230557Sjimharris                    String sep = "";
366230557Sjimharris                    for (Symbol sym: scope.getSymbols()) {
367230557Sjimharris                        out.print(sep);
368230557Sjimharris                        out.print(sym.name);
369230557Sjimharris                        sep = ",";
370230557Sjimharris                    }
371230557Sjimharris                    out.println("]");
372230557Sjimharris                    break;
373230557Sjimharris                }
374230557Sjimharris
375230557Sjimharris                case FULL: {
376230557Sjimharris                    indent();
377230557Sjimharris                    out.println(label);
378230557Sjimharris
379230557Sjimharris                    indent(+1);
380230557Sjimharris                    printFullScopeImpl(scope);
381230557Sjimharris                    indent(-1);
382230557Sjimharris                    break;
383230557Sjimharris                }
384230557Sjimharris            }
385230557Sjimharris        }
386230557Sjimharris    }
387230557Sjimharris
388230557Sjimharris    void printFullScopeImpl(Scope scope) {
389230557Sjimharris        indent();
390230557Sjimharris        out.println(scope.getClass().getName());
391230557Sjimharris        printSymbol("owner", scope.owner, Details.SUMMARY);
392230557Sjimharris        if (SCOPE_IMPL_CLASS.equals(scope.getClass().getName())) {
393230557Sjimharris            printScope("next", (Scope) getField(scope, scope.getClass(), "next"), Details.SUMMARY);
394230557Sjimharris            printObject("shared", getField(scope, scope.getClass(), "shared"), Details.SUMMARY);
395230557Sjimharris            Object[] table = (Object[]) getField(scope, scope.getClass(), "table");
396230557Sjimharris            for (int i = 0; i < table.length; i++) {
397230557Sjimharris                if (i > 0)
398230557Sjimharris                    out.print(", ");
399230557Sjimharris                else
400230557Sjimharris                    indent();
401230557Sjimharris                out.print(i + ":" + entryToString(table[i], table, false));
402230557Sjimharris            }
403230557Sjimharris            out.println();
404230557Sjimharris        } else if (FILTER_SCOPE_CLASS.equals(scope.getClass().getName())) {
405230557Sjimharris            printScope("origin",
406230557Sjimharris                    (Scope) getField(scope, scope.getClass(), "origin"), Details.FULL);
407230557Sjimharris        } else if (scope instanceof CompoundScope) {
408230557Sjimharris            printList("delegates", (List<?>) getField(scope, CompoundScope.class, "subScopes"));
409230557Sjimharris        } else {
410230557Sjimharris            for (Symbol sym : scope.getSymbols()) {
411230557Sjimharris                printSymbol(sym.name.toString(), sym, Details.SUMMARY);
412230557Sjimharris            }
413230557Sjimharris        }
414230557Sjimharris    }
415230557Sjimharris        //where:
416230557Sjimharris        static final String SCOPE_IMPL_CLASS = "com.sun.tools.javac.code.Scope$ScopeImpl";
417230557Sjimharris        static final String FILTER_SCOPE_CLASS = "com.sun.tools.javac.code.Scope$FilterImportScope";
418230557Sjimharris
419230557Sjimharris    /**
420230557Sjimharris     * Create a string showing the contents of an entry, using the table
421230557Sjimharris     * to help identify cross-references to other entries in the table.
422230557Sjimharris     * @param e the entry to be shown
423230557Sjimharris     * @param table the table containing the other entries
424230557Sjimharris     */
425230557Sjimharris    String entryToString(Object e, Object[] table, boolean ref) {
426230557Sjimharris        if (e == null)
427230557Sjimharris            return "null";
428230557Sjimharris        Symbol sym = (Symbol) getField(e, e.getClass(), "sym");
429230557Sjimharris        if (sym == null)
430230557Sjimharris            return "sent"; // sentinel
431230557Sjimharris        if (ref) {
432230557Sjimharris            int index = indexOf(table, e);
433230557Sjimharris            if (index != -1)
434230557Sjimharris                return String.valueOf(index);
435230557Sjimharris        }
436230557Sjimharris        Scope scope = (Scope) getField(e, e.getClass(), "scope");
437230557Sjimharris        return "(" + sym.name + ":" + sym
438230557Sjimharris                + ",shdw:" + entryToString(callMethod(e, e.getClass(), "next"), table, true)
439230557Sjimharris                + ",sibl:" + entryToString(getField(e, e.getClass(), "sibling"), table, true)
440230557Sjimharris                + ((sym.owner != scope.owner)
441230557Sjimharris                    ? (",BOGUS[" + sym.owner + "," + scope.owner + "]")
442230557Sjimharris                    : "")
443230557Sjimharris                + ")";
444230557Sjimharris    }
445230557Sjimharris
446230557Sjimharris    <T> int indexOf(T[] array, T item) {
447230557Sjimharris        for (int i = 0; i < array.length; i++) {
448230557Sjimharris            if (array[i] == item)
449230557Sjimharris                return i;
450230557Sjimharris        }
451230557Sjimharris        return -1;
452230557Sjimharris    }
453230557Sjimharris
454230557Sjimharris    public void printSource(String label, JCTree tree) {
455230557Sjimharris        printString(label, Pretty.toSimpleString(tree, maxSrcLength));
456230557Sjimharris    }
457230557Sjimharris
458230557Sjimharris    public void printString(String label, String text) {
459230557Sjimharris        indent();
460230557Sjimharris        out.print(label);
461230557Sjimharris        out.print(": ");
462230557Sjimharris        out.print(text);
463230557Sjimharris        out.println();
464230557Sjimharris    }
465230557Sjimharris
466230557Sjimharris    public void printSymbol(String label, Symbol symbol) {
467230557Sjimharris        printSymbol(label, symbol, Details.FULL);
468230557Sjimharris    }
469230557Sjimharris
470230557Sjimharris    protected void printSymbol(String label, Symbol sym, Details details) {
471230557Sjimharris        if (sym == null) {
472230557Sjimharris            printNull(label);
473230557Sjimharris        } else {
474230557Sjimharris            switch (details) {
475230557Sjimharris            case SUMMARY:
476230557Sjimharris                printString(label, toString(sym));
477230557Sjimharris                break;
478230557Sjimharris
479230557Sjimharris            case FULL:
480230557Sjimharris                indent();
481230557Sjimharris                out.print(label);
482230557Sjimharris                out.println(": " +
483230557Sjimharris                        info(sym.getClass(),
484230557Sjimharris                            String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
485230557Sjimharris                            sym.getKind())
486230557Sjimharris                        + " " + sym.name
487230557Sjimharris                        + " " + hashString(sym));
488230557Sjimharris
489230557Sjimharris                indent(+1);
490230557Sjimharris                if (showSrc) {
491230557Sjimharris                    JCTree tree = (JCTree) trees.getTree(sym);
492230557Sjimharris                    if (tree != null)
493230557Sjimharris                        printSource("src", tree);
494230557Sjimharris                }
495230557Sjimharris                printString("flags", String.format("0x%x--%s",
496230557Sjimharris                        sym.flags_field, Flags.toString(sym.flags_field)));
497230557Sjimharris                printObject("completer", sym.completer, Details.SUMMARY); // what if too long?
498230557Sjimharris                printSymbol("owner", sym.owner, Details.SUMMARY);
499230557Sjimharris                printType("type", sym.type, Details.SUMMARY);
500230557Sjimharris                printType("erasure", sym.erasure_field, Details.SUMMARY);
501230557Sjimharris                sym.accept(symVisitor, null);
502230557Sjimharris                printAnnotations("annotations", sym.getMetadata(), Details.SUMMARY);
503230557Sjimharris                indent(-1);
504230557Sjimharris            }
505230557Sjimharris        }
506230557Sjimharris    }
507230557Sjimharris
508230557Sjimharris    protected String toString(Symbol sym) {
509230557Sjimharris        return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym);
510230557Sjimharris    }
511230557Sjimharris
512230557Sjimharris    protected void printTree(String label, JCTree tree) {
513230557Sjimharris        if (tree == null) {
514230557Sjimharris            printNull(label);
515230557Sjimharris        } else {
516230557Sjimharris            indent();
517230557Sjimharris            String ext;
518230557Sjimharris            try {
519230557Sjimharris                ext = tree.getKind().name();
520230557Sjimharris            } catch (Throwable t) {
521230557Sjimharris                ext = "n/a";
522230557Sjimharris            }
523230557Sjimharris            out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext));
524230557Sjimharris            if (showPositions) {
525230557Sjimharris                // We can always get start position, but to get end position
526230557Sjimharris                // and/or line+offset, we would need a JCCompilationUnit
527230557Sjimharris                out.print(" pos:" + tree.pos);
528230557Sjimharris            }
529230557Sjimharris            if (showTreeTypes && tree.type != null)
530230557Sjimharris                out.print(" type:" + toString(tree.type));
531230557Sjimharris            Symbol sym;
532230557Sjimharris            if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null)
533230557Sjimharris                out.print(" sym:" + toString(sym));
534230557Sjimharris            out.println();
535230557Sjimharris
536230557Sjimharris            indent(+1);
537230557Sjimharris            if (showSrc) {
538230557Sjimharris                indent();
539230557Sjimharris                out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength));
540230557Sjimharris            }
541230557Sjimharris            tree.accept(treeVisitor);
542230557Sjimharris            indent(-1);
543230557Sjimharris        }
544230557Sjimharris    }
545230557Sjimharris
546230557Sjimharris    public void printType(String label, Type type) {
547230557Sjimharris        printType(label, type, Details.FULL);
548230557Sjimharris    }
549230557Sjimharris
550230557Sjimharris    protected void printType(String label, Type type, Details details) {
551230557Sjimharris        if (type == null)
552230557Sjimharris            printNull(label);
553230557Sjimharris        else {
554230557Sjimharris            switch (details) {
555230557Sjimharris                case SUMMARY:
556230557Sjimharris                    printString(label, toString(type));
557230557Sjimharris                    break;
558230557Sjimharris
559230557Sjimharris                case FULL:
560230557Sjimharris                    indent();
561230557Sjimharris                    out.print(label);
562230557Sjimharris                    out.println(": " + info(type.getClass(), type.getTag(), type.getKind())
563230557Sjimharris                            + " " + hashString(type));
564230557Sjimharris
565230557Sjimharris                    indent(+1);
566230557Sjimharris                    printSymbol("tsym", type.tsym, Details.SUMMARY);
567230557Sjimharris                    printObject("constValue", type.constValue(), Details.SUMMARY);
568230557Sjimharris                    printObject("annotations", type.getAnnotationMirrors(), Details.SUMMARY);
569230557Sjimharris                    type.accept(typeVisitor, null);
570230557Sjimharris                    indent(-1);
571230557Sjimharris            }
572230557Sjimharris        }
573230557Sjimharris    }
574230557Sjimharris
575230557Sjimharris    protected String toString(Type type) {
576230557Sjimharris        return (printer != null) ? printer.visit(type, locale) : String.valueOf(type);
577230557Sjimharris    }
578230557Sjimharris
579230557Sjimharris    protected String hashString(Object obj) {
580230557Sjimharris        return String.format("#%x", obj.hashCode());
581230557Sjimharris    }
582230557Sjimharris
583230557Sjimharris    protected String info(Class<?> clazz, Object internal, Object external) {
584230557Sjimharris        return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external);
585230557Sjimharris    }
586230557Sjimharris
587230557Sjimharris    private int indent = 0;
588230557Sjimharris
589230557Sjimharris    protected void indent() {
590230557Sjimharris        for (int i = 0; i < indent; i++) {
591230557Sjimharris            out.print("  ");
592230557Sjimharris        }
593230557Sjimharris    }
594230557Sjimharris
595230557Sjimharris    protected void indent(int n) {
596230557Sjimharris        indent += n;
597230557Sjimharris    }
598230557Sjimharris
599230557Sjimharris    protected Object getField(Object o, Class<?> clazz, String name) {
600230557Sjimharris        try {
601230557Sjimharris            Field f = clazz.getDeclaredField(name);
602230557Sjimharris            boolean prev = f.isAccessible();
603230557Sjimharris            f.setAccessible(true);
604230557Sjimharris            try {
605230557Sjimharris                return f.get(o);
606230557Sjimharris            } finally {
607230557Sjimharris                f.setAccessible(prev);
608230557Sjimharris            }
609230557Sjimharris        } catch (ReflectiveOperationException e) {
610230557Sjimharris            return e;
611230557Sjimharris        } catch (SecurityException e) {
612230557Sjimharris            return e;
613230557Sjimharris        }
614230557Sjimharris    }
615230557Sjimharris
616230557Sjimharris    protected Object callMethod(Object o, Class<?> clazz, String name) {
617230557Sjimharris        try {
618230557Sjimharris            Method m = clazz.getDeclaredMethod(name);
619230557Sjimharris            boolean prev = m.isAccessible();
620230557Sjimharris            m.setAccessible(true);
621230557Sjimharris            try {
622230557Sjimharris                return m.invoke(o);
623230557Sjimharris            } finally {
624230557Sjimharris                m.setAccessible(prev);
625230557Sjimharris            }
626230557Sjimharris        } catch (ReflectiveOperationException e) {
627230557Sjimharris            return e;
628230557Sjimharris        } catch (SecurityException e) {
629230557Sjimharris            return e;
630230557Sjimharris        }
631230557Sjimharris    }
632230557Sjimharris
633230557Sjimharris    // </editor-fold>
634230557Sjimharris
635230557Sjimharris    // <editor-fold defaultstate="collapsed" desc="JCTree visitor methods">
636230557Sjimharris
637230557Sjimharris    protected JCTree.Visitor treeVisitor = new TreeVisitor();
638230557Sjimharris
639230557Sjimharris    /**
640230557Sjimharris     * Default visitor class for JCTree (AST) objects.
641230557Sjimharris     */
642230557Sjimharris    public class TreeVisitor extends JCTree.Visitor {
643230557Sjimharris        @Override
644230557Sjimharris        public void visitTopLevel(JCCompilationUnit tree) {
645230557Sjimharris            printList("packageAnnotations", tree.getPackageAnnotations());
646230557Sjimharris            printList("defs", tree.defs);
647230557Sjimharris        }
648230557Sjimharris
649230557Sjimharris        @Override
650230557Sjimharris        public void visitPackageDef(JCPackageDecl tree) {
651230557Sjimharris            printTree("pid", tree.pid);
652230557Sjimharris        }
653230557Sjimharris
654230557Sjimharris        @Override
655230557Sjimharris        public void visitImport(JCImport tree) {
656230557Sjimharris            printTree("qualid", tree.qualid);
657230557Sjimharris        }
658230557Sjimharris
659230557Sjimharris        @Override
660230557Sjimharris        public void visitClassDef(JCClassDecl tree) {
661230557Sjimharris            printName("name", tree.name);
662230557Sjimharris            printTree("mods", tree.mods);
663230557Sjimharris            printList("typarams", tree.typarams);
664230557Sjimharris            printTree("extending", tree.extending);
665230557Sjimharris            printList("implementing", tree.implementing);
666230557Sjimharris            printList("defs", tree.defs);
667230557Sjimharris        }
668230557Sjimharris
669230557Sjimharris        @Override
670230557Sjimharris        public void visitMethodDef(JCMethodDecl tree) {
671230557Sjimharris            printName("name", tree.name);
672230557Sjimharris            printTree("mods", tree.mods);
673230557Sjimharris            printTree("restype", tree.restype);
674230557Sjimharris            printList("typarams", tree.typarams);
675230557Sjimharris            printTree("recvparam", tree.recvparam);
676230557Sjimharris            printList("params", tree.params);
677230557Sjimharris            printList("thrown", tree.thrown);
678230557Sjimharris            printTree("defaultValue", tree.defaultValue);
679230557Sjimharris            printTree("body", tree.body);
680230557Sjimharris        }
681230557Sjimharris
682230557Sjimharris        @Override
683230557Sjimharris        public void visitVarDef(JCVariableDecl tree) {
684230557Sjimharris            printName("name", tree.name);
685230557Sjimharris            printTree("mods", tree.mods);
686230557Sjimharris            printTree("vartype", tree.vartype);
687230557Sjimharris            printTree("init", tree.init);
688230557Sjimharris        }
689230557Sjimharris
690230557Sjimharris        @Override
691230557Sjimharris        public void visitSkip(JCSkip tree) {
692230557Sjimharris        }
693230557Sjimharris
694230557Sjimharris        @Override
695230557Sjimharris        public void visitBlock(JCBlock tree) {
696230557Sjimharris            printList("stats", tree.stats);
697230557Sjimharris        }
698230557Sjimharris
699230557Sjimharris        @Override
700230557Sjimharris        public void visitDoLoop(JCDoWhileLoop tree) {
701230557Sjimharris            printTree("body", tree.body);
702230557Sjimharris            printTree("cond", tree.cond);
703230557Sjimharris        }
704230557Sjimharris
705230557Sjimharris        @Override
706230557Sjimharris        public void visitWhileLoop(JCWhileLoop tree) {
707230557Sjimharris            printTree("cond", tree.cond);
708230557Sjimharris            printTree("body", tree.body);
709230557Sjimharris        }
710230557Sjimharris
711230557Sjimharris        @Override
712230557Sjimharris        public void visitForLoop(JCForLoop tree) {
713230557Sjimharris            printList("init", tree.init);
714230557Sjimharris            printTree("cond", tree.cond);
715230557Sjimharris            printList("step", tree.step);
716230557Sjimharris            printTree("body", tree.body);
717230557Sjimharris        }
718230557Sjimharris
719230557Sjimharris        @Override
720230557Sjimharris        public void visitForeachLoop(JCEnhancedForLoop tree) {
721230557Sjimharris            printTree("var", tree.var);
722230557Sjimharris            printTree("expr", tree.expr);
723230557Sjimharris            printTree("body", tree.body);
724230557Sjimharris        }
725230557Sjimharris
726230557Sjimharris        @Override
727230557Sjimharris        public void visitLabelled(JCLabeledStatement tree) {
728230557Sjimharris            printTree("body", tree.body);
729230557Sjimharris        }
730230557Sjimharris
731230557Sjimharris        @Override
732230557Sjimharris        public void visitSwitch(JCSwitch tree) {
733230557Sjimharris            printTree("selector", tree.selector);
734230557Sjimharris            printList("cases", tree.cases);
735230557Sjimharris        }
736230557Sjimharris
737230557Sjimharris        @Override
738230557Sjimharris        public void visitCase(JCCase tree) {
739230557Sjimharris            printTree("pat", tree.pat);
740230557Sjimharris            printList("stats", tree.stats);
741230557Sjimharris        }
742230557Sjimharris
743230557Sjimharris        @Override
744230557Sjimharris        public void visitSynchronized(JCSynchronized tree) {
745230557Sjimharris            printTree("lock", tree.lock);
746230557Sjimharris            printTree("body", tree.body);
747230557Sjimharris        }
748230557Sjimharris
749230557Sjimharris        @Override
750230557Sjimharris        public void visitTry(JCTry tree) {
751230557Sjimharris            printList("resources", tree.resources);
752230557Sjimharris            printTree("body", tree.body);
753230557Sjimharris            printList("catchers", tree.catchers);
754230557Sjimharris            printTree("finalizer", tree.finalizer);
755230557Sjimharris        }
756230557Sjimharris
757230557Sjimharris        @Override
758230557Sjimharris        public void visitCatch(JCCatch tree) {
759230557Sjimharris            printTree("param", tree.param);
760230557Sjimharris            printTree("body", tree.body);
761230557Sjimharris        }
762230557Sjimharris
763230557Sjimharris        @Override
764230557Sjimharris        public void visitConditional(JCConditional tree) {
765230557Sjimharris            printTree("cond", tree.cond);
766230557Sjimharris            printTree("truepart", tree.truepart);
767230557Sjimharris            printTree("falsepart", tree.falsepart);
768230557Sjimharris        }
769230557Sjimharris
770230557Sjimharris        @Override
771230557Sjimharris        public void visitIf(JCIf tree) {
772230557Sjimharris            printTree("cond", tree.cond);
773230557Sjimharris            printTree("thenpart", tree.thenpart);
774230557Sjimharris            printTree("elsepart", tree.elsepart);
775230557Sjimharris        }
776230557Sjimharris
777230557Sjimharris        @Override
778230557Sjimharris        public void visitExec(JCExpressionStatement tree) {
779230557Sjimharris            printTree("expr", tree.expr);
780230557Sjimharris        }
781230557Sjimharris
782230557Sjimharris        @Override
783230557Sjimharris        public void visitBreak(JCBreak tree) {
784230557Sjimharris            printName("label", tree.label);
785230557Sjimharris        }
786230557Sjimharris
787230557Sjimharris        @Override
788230557Sjimharris        public void visitContinue(JCContinue tree) {
789230557Sjimharris            printName("label", tree.label);
790230557Sjimharris        }
791230557Sjimharris
792230557Sjimharris        @Override
793230557Sjimharris        public void visitReturn(JCReturn tree) {
794230557Sjimharris            printTree("expr", tree.expr);
795230557Sjimharris        }
796230557Sjimharris
797230557Sjimharris        @Override
798230557Sjimharris        public void visitThrow(JCThrow tree) {
799230557Sjimharris            printTree("expr", tree.expr);
800        }
801
802        @Override
803        public void visitAssert(JCAssert tree) {
804            printTree("cond", tree.cond);
805            printTree("detail", tree.detail);
806        }
807
808        @Override
809        public void visitApply(JCMethodInvocation tree) {
810            printList("typeargs", tree.typeargs);
811            printTree("meth", tree.meth);
812            printList("args", tree.args);
813        }
814
815        @Override
816        public void visitNewClass(JCNewClass tree) {
817            printTree("encl", tree.encl);
818            printList("typeargs", tree.typeargs);
819            printTree("clazz", tree.clazz);
820            printList("args", tree.args);
821            printTree("def", tree.def);
822        }
823
824        @Override
825        public void visitNewArray(JCNewArray tree) {
826            printList("annotations", tree.annotations);
827            printTree("elemtype", tree.elemtype);
828            printList("dims", tree.dims);
829            printList("dimAnnotations", tree.dimAnnotations);
830            printList("elems", tree.elems);
831        }
832
833        @Override
834        public void visitLambda(JCLambda tree) {
835            printTree("body", tree.body);
836            printList("params", tree.params);
837        }
838
839        @Override
840        public void visitParens(JCParens tree) {
841            printTree("expr", tree.expr);
842        }
843
844        @Override
845        public void visitAssign(JCAssign tree) {
846            printTree("lhs", tree.lhs);
847            printTree("rhs", tree.rhs);
848        }
849
850        @Override
851        public void visitAssignop(JCAssignOp tree) {
852            printTree("lhs", tree.lhs);
853            printTree("rhs", tree.rhs);
854        }
855
856        @Override
857        public void visitUnary(JCUnary tree) {
858            printTree("arg", tree.arg);
859        }
860
861        @Override
862        public void visitBinary(JCBinary tree) {
863            printTree("lhs", tree.lhs);
864            printTree("rhs", tree.rhs);
865        }
866
867        @Override
868        public void visitTypeCast(JCTypeCast tree) {
869            printTree("clazz", tree.clazz);
870            printTree("expr", tree.expr);
871        }
872
873        @Override
874        public void visitTypeTest(JCInstanceOf tree) {
875            printTree("expr", tree.expr);
876            printTree("clazz", tree.clazz);
877        }
878
879        @Override
880        public void visitIndexed(JCArrayAccess tree) {
881            printTree("indexed", tree.indexed);
882            printTree("index", tree.index);
883        }
884
885        @Override
886        public void visitSelect(JCFieldAccess tree) {
887            printTree("selected", tree.selected);
888        }
889
890        @Override
891        public void visitReference(JCMemberReference tree) {
892            printTree("expr", tree.expr);
893            printList("typeargs", tree.typeargs);
894        }
895
896        @Override
897        public void visitIdent(JCIdent tree) {
898            printName("name", tree.name);
899        }
900
901        @Override
902        public void visitLiteral(JCLiteral tree) {
903            printString("value", Pretty.toSimpleString(tree, 32));
904        }
905
906        @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 visitIdentifier(IdentifierTree node, Void p) {
1048            printName("name", node.getName());
1049            return visitTree(node, null);
1050        }
1051
1052        public Void visitIndex(IndexTree node, Void p) {
1053            printString("kind", node.getKind().name());
1054            printDocTree("term", node.getSearchTerm());
1055            printList("desc", node.getDescription());
1056            return visitInlineTag(node, p);
1057        }
1058
1059        public Void visitInheritDoc(InheritDocTree node, Void p) {
1060            return visitInlineTag(node, null);
1061        }
1062
1063        public Void visitLink(LinkTree node, Void p) {
1064            printString("kind", node.getKind().name());
1065            printDocTree("ref", node.getReference());
1066            printList("list", node.getLabel());
1067            return visitInlineTag(node, null);
1068        }
1069
1070        public Void visitLiteral(LiteralTree node, Void p) {
1071            printString("kind", node.getKind().name());
1072            printDocTree("body", node.getBody());
1073            return visitInlineTag(node, null);
1074        }
1075
1076        public Void visitParam(ParamTree node, Void p) {
1077            printString("isTypeParameter", String.valueOf(node.isTypeParameter()));
1078            printString("kind", node.getKind().name());
1079            printList("desc", node.getDescription());
1080            return visitBlockTag(node, null);
1081        }
1082
1083        public Void visitReference(ReferenceTree node, Void p) {
1084            printString("signature", node.getSignature());
1085            return visitTree(node, null);
1086        }
1087
1088        public Void visitReturn(ReturnTree node, Void p) {
1089            printList("desc", node.getDescription());
1090            return visitBlockTag(node, null);
1091        }
1092
1093        public Void visitSee(SeeTree node, Void p) {
1094            printList("ref", node.getReference());
1095            return visitBlockTag(node, null);
1096        }
1097
1098        public Void visitSerial(SerialTree node, Void p) {
1099            printList("desc", node.getDescription());
1100            return visitBlockTag(node, null);
1101        }
1102
1103        public Void visitSerialData(SerialDataTree node, Void p) {
1104            printList("desc", node.getDescription());
1105            return visitBlockTag(node, null);
1106        }
1107
1108        public Void visitSerialField(SerialFieldTree node, Void p) {
1109            printDocTree("name", node.getName());
1110            printDocTree("type", node.getType());
1111            printList("desc", node.getDescription());
1112            return visitBlockTag(node, null);
1113        }
1114
1115        public Void visitSince(SinceTree node, Void p) {
1116            printList("body", node.getBody());
1117            return visitBlockTag(node, null);
1118        }
1119
1120        public Void visitStartElement(StartElementTree node, Void p) {
1121            printName("name", node.getName());
1122            printList("attrs", node.getAttributes());
1123            printString("selfClosing", String.valueOf(node.isSelfClosing()));
1124            return visitBlockTag(node, null);
1125        }
1126
1127        public Void visitText(TextTree node, Void p) {
1128            printLimitedEscapedString("body", node.getBody());
1129            return visitTree(node, null);
1130        }
1131
1132        public Void visitThrows(ThrowsTree node, Void p) {
1133            printDocTree("name", node.getExceptionName());
1134            printList("desc", node.getDescription());
1135            return visitBlockTag(node, null);
1136        }
1137
1138        public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
1139            printString("name", node.getTagName());
1140            printList("content", node.getContent());
1141            return visitBlockTag(node, null);
1142        }
1143
1144        public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
1145            printString("name", node.getTagName());
1146            printList("content", node.getContent());
1147            return visitInlineTag(node, null);
1148        }
1149
1150        public Void visitValue(ValueTree node, Void p) {
1151            printDocTree("value", node.getReference());
1152            return visitInlineTag(node, null);
1153        }
1154
1155        public Void visitVersion(VersionTree node, Void p) {
1156            printList("body", node.getBody());
1157            return visitBlockTag(node, null);
1158        }
1159
1160        public Void visitOther(DocTree node, Void p) {
1161            return visitTree(node, null);
1162        }
1163
1164        public Void visitBlockTag(DocTree node, Void p) {
1165            return visitTree(node, null);
1166        }
1167
1168        public Void visitInlineTag(DocTree node, Void p) {
1169            return visitTree(node, null);
1170        }
1171
1172        public Void visitTree(DocTree node, Void p) {
1173            return null;
1174        }
1175    }
1176
1177    // </editor-fold>
1178
1179    // <editor-fold defaultstate="collapsed" desc="Symbol visitor">
1180
1181    protected Symbol.Visitor<Void,Void> symVisitor = new SymbolVisitor();
1182
1183    /**
1184     * Default visitor class for Symbol objects.
1185     * Note: each visitXYZ method ends by calling the corresponding
1186     * visit method for its superclass.
1187     */
1188    class SymbolVisitor implements Symbol.Visitor<Void,Void> {
1189        @Override
1190        public Void visitClassSymbol(ClassSymbol sym, Void ignore) {
1191            printName("fullname", sym.fullname);
1192            printName("flatname", sym.flatname);
1193            printScope("members", sym.members_field);
1194            printFileObject("sourcefile", sym.sourcefile);
1195            printFileObject("classfile", sym.classfile);
1196            // trans-local?
1197            // pool?
1198            return visitTypeSymbol(sym, null);
1199        }
1200
1201        @Override
1202        public Void visitMethodSymbol(MethodSymbol sym, Void ignore) {
1203            // code
1204            printList("params", sym.params);
1205            printList("savedParameterNames", sym.savedParameterNames);
1206            return visitSymbol(sym, null);
1207        }
1208
1209        @Override
1210        public Void visitPackageSymbol(PackageSymbol sym, Void ignore) {
1211            printName("fullname", sym.fullname);
1212            printScope("members", sym.members_field);
1213            printSymbol("package-info", sym.package_info, Details.SUMMARY);
1214            return visitTypeSymbol(sym, null);
1215        }
1216
1217        @Override
1218        public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) {
1219            printInt("opcode", sym.opcode);
1220            return visitMethodSymbol(sym, null);
1221        }
1222
1223        @Override
1224        public Void visitVarSymbol(VarSymbol sym, Void ignore) {
1225            printInt("pos", sym.pos);
1226            printInt("adm", sym.adr);
1227            // data is a private field, and the standard accessors may
1228            // mutate it as part of lazy evaluation. Therefore, use
1229            // reflection to get the raw data.
1230            printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY);
1231            return visitSymbol(sym, null);
1232        }
1233
1234        @Override
1235        public Void visitTypeSymbol(TypeSymbol sym, Void ignore) {
1236            return visitSymbol(sym, null);
1237        }
1238
1239        @Override
1240        public Void visitSymbol(Symbol sym, Void ignore) {
1241            return null;
1242        }
1243    }
1244
1245    // </editor-fold>
1246
1247    // <editor-fold defaultstate="collapsed" desc="Type visitor">
1248
1249    protected Type.Visitor<Void,Void> typeVisitor = new TypeVisitor();
1250
1251    /**
1252     * Default visitor class for Type objects.
1253     * Note: each visitXYZ method ends by calling the corresponding
1254     * visit method for its superclass.
1255     */
1256    public class TypeVisitor implements Type.Visitor<Void,Void> {
1257        public Void visitArrayType(ArrayType type, Void ignore) {
1258            printType("elemType", type.elemtype, Details.FULL);
1259            return visitType(type, null);
1260        }
1261
1262        public Void visitCapturedType(CapturedType type, Void ignore) {
1263            printType("wildcard", type.wildcard, Details.FULL);
1264            return visitTypeVar(type, null);
1265        }
1266
1267        public Void visitClassType(ClassType type, Void ignore) {
1268            printType("outer", type.getEnclosingType(), Details.SUMMARY);
1269            printList("typarams", type.typarams_field);
1270            printList("allparams", type.allparams_field);
1271            printType("supertype", type.supertype_field, Details.SUMMARY);
1272            printList("interfaces", type.interfaces_field);
1273            printList("allinterfaces", type.all_interfaces_field);
1274            return visitType(type, null);
1275        }
1276
1277        public Void visitErrorType(ErrorType type, Void ignore) {
1278            printType("originalType", type.getOriginalType(), Details.FULL);
1279            return visitClassType(type, null);
1280        }
1281
1282        public Void visitForAll(ForAll type, Void ignore) {
1283            printList("tvars", type.tvars);
1284            return visitDelegatedType(type);
1285        }
1286
1287        public Void visitMethodType(MethodType type, Void ignore) {
1288            printList("argtypes", type.argtypes);
1289            printType("restype", type.restype, Details.FULL);
1290            printList("thrown", type.thrown);
1291            printType("recvtype", type.recvtype, Details.FULL);
1292            return visitType(type, null);
1293        }
1294
1295        public Void visitModuleType(ModuleType type, Void ignore) {
1296            return visitType(type, null);
1297        }
1298
1299        public Void visitPackageType(PackageType type, Void ignore) {
1300            return visitType(type, null);
1301        }
1302
1303        public Void visitTypeVar(TypeVar type, Void ignore) {
1304            // For TypeVars (and not subtypes), the bound should always be
1305            // null or bot. So, only print the bound for subtypes of TypeVar,
1306            // or if the bound is (erroneously) not null or bot.
1307            if (!type.hasTag(TypeTag.TYPEVAR)
1308                    || !(type.bound == null || type.bound.hasTag(TypeTag.BOT))) {
1309                printType("bound", type.bound, Details.FULL);
1310            }
1311            printType("lower", type.lower, Details.FULL);
1312            return visitType(type, null);
1313        }
1314
1315        public Void visitUndetVar(UndetVar type, Void ignore) {
1316            for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
1317                printList("bounds." + ib, type.getBounds(ib));
1318            printInt("declaredCount", type.declaredCount);
1319            printType("inst", type.getInst(), Details.SUMMARY);
1320            return visitDelegatedType(type);
1321        }
1322
1323        public Void visitWildcardType(WildcardType type, Void ignore) {
1324            printType("type", type.type, Details.SUMMARY);
1325            printString("kind", type.kind.name());
1326            printType("bound", type.bound, Details.SUMMARY);
1327            return visitType(type, null);
1328        }
1329
1330        protected Void visitDelegatedType(DelegatedType type) {
1331            printType("qtype", type.qtype, Details.FULL);
1332            return visitType(type, null);
1333        }
1334
1335        public Void visitType(Type type, Void ignore) {
1336            return null;
1337        }
1338    }
1339
1340    // </editor-fold>
1341
1342    // <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
1343
1344    protected Attribute.Visitor attrVisitor = new AttributeVisitor();
1345
1346    /**
1347     * Default visitor class for Attribute (annotation) objects.
1348     */
1349    public class AttributeVisitor implements Attribute.Visitor {
1350
1351        public void visitConstant(Attribute.Constant a) {
1352            printObject("value", a.value, Details.SUMMARY);
1353            visitAttribute(a);
1354        }
1355
1356        public void visitClass(Attribute.Class a) {
1357            printObject("classType", a.classType, Details.SUMMARY);
1358            visitAttribute(a);
1359        }
1360
1361        public void visitCompound(Attribute.Compound a) {
1362            if (a instanceof Attribute.TypeCompound) {
1363                Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
1364                // consider a custom printer?
1365                printObject("position", ta.position, Details.SUMMARY);
1366            }
1367            printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
1368            printList("values", a.values);
1369            visitAttribute(a);
1370        }
1371
1372        public void visitArray(Attribute.Array a) {
1373            printList("values", Arrays.asList(a.values));
1374            visitAttribute(a);
1375        }
1376
1377        public void visitEnum(Attribute.Enum a) {
1378            printSymbol("value", a.value, Details.SUMMARY);
1379            visitAttribute(a);
1380        }
1381
1382        public void visitError(Attribute.Error a) {
1383            visitAttribute(a);
1384        }
1385
1386        public void visitAttribute(Attribute a) {
1387            printType("type", a.type, Details.SUMMARY);
1388        }
1389
1390    }
1391    // </editor-fold>
1392
1393    // <editor-fold defaultstate="collapsed" desc="Utility front end">
1394
1395    /**
1396     * Utility class to invoke DPrinter from the command line.
1397     */
1398    static class Main {
1399        public static void main(String... args) throws IOException {
1400            Main m = new Main();
1401            PrintWriter out = new PrintWriter(System.out);
1402            try {
1403                if (args.length == 0)
1404                    m.usage(out);
1405                else
1406                    m.run(out, args);
1407            } finally {
1408                out.flush();
1409            }
1410        }
1411
1412        void usage(PrintWriter out) {
1413            out.println("Usage:");
1414            out.println("  java " + Main.class.getName() + " mode [options] [javac-options]");
1415            out.print("where mode is one of: ");
1416            String sep = "";
1417            for (Handler h: getHandlers().values()) {
1418                out.print(sep);
1419                out.print(h.name);
1420                sep = ", ";
1421            }
1422            out.println();
1423            out.println("and where options include:");
1424            out.println("  -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1425            out.println("  -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1426            out.println("  -showPositions");
1427            out.println("  -showSource");
1428            out.println("  -showTreeSymbols");
1429            out.println("  -showTreeTypes");
1430            out.println("  -hideEmptyItems");
1431            out.println("  -hideNulls");
1432        }
1433
1434        void run(PrintWriter out, String... args) throws IOException {
1435            JavaCompiler c = ToolProvider.getSystemJavaCompiler();
1436            StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
1437
1438            // DPrinter options
1439            final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
1440            final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
1441            boolean showPositions = false;
1442            boolean showSource = false;
1443            boolean showTreeSymbols = false;
1444            boolean showTreeTypes = false;
1445            boolean showEmptyItems = true;
1446            boolean showNulls = true;
1447
1448            // javac options
1449            Collection<String> options = new ArrayList<String>();
1450            Collection<File> files = new ArrayList<File>();
1451            String classpath = null;
1452            String classoutdir = null;
1453
1454            final Handler h = getHandlers().get(args[0]);
1455            if (h == null)
1456                throw new IllegalArgumentException(args[0]);
1457
1458            for (int i = 1; i < args.length; i++) {
1459                String arg = args[i];
1460                if (arg.equals("-before") && i + 1 < args.length) {
1461                    before.add(getKind(args[++i]));
1462                } else if (arg.equals("-after") && i + 1 < args.length) {
1463                    after.add(getKind(args[++i]));
1464                } else if (arg.equals("-showPositions")) {
1465                    showPositions = true;
1466                } else if (arg.equals("-showSource")) {
1467                    showSource = true;
1468                } else if (arg.equals("-showTreeSymbols")) {
1469                    showTreeSymbols = true;
1470                } else if (arg.equals("-showTreeTypes")) {
1471                    showTreeTypes = true;
1472                } else if (arg.equals("-hideEmptyLists")) {
1473                    showEmptyItems = false;
1474                } else if (arg.equals("-hideNulls")) {
1475                    showNulls = false;
1476                } else if (arg.equals("-classpath") && i + 1 < args.length) {
1477                    classpath = args[++i];
1478                } else if (arg.equals("-d") && i + 1 < args.length) {
1479                    classoutdir = args[++i];
1480                } else if (arg.startsWith("-")) {
1481                    int n = c.isSupportedOption(arg);
1482                    if (n < 0) throw new IllegalArgumentException(arg);
1483                    options.add(arg);
1484                    while (n > 0) options.add(args[++i]);
1485                } else if (arg.endsWith(".java")) {
1486                    files.add(new File(arg));
1487                }
1488            }
1489
1490            if (classoutdir != null) {
1491                fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
1492            }
1493
1494            if (classpath != null) {
1495                Collection<File> path = new ArrayList<File>();
1496                for (String p: classpath.split(File.pathSeparator)) {
1497                    if (p.isEmpty()) continue;
1498                    File f = new File(p);
1499                    if (f.exists()) path.add(f);
1500                }
1501                fm.setLocation(StandardLocation.CLASS_PATH, path);
1502            }
1503            Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
1504
1505            JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
1506            final Trees trees = Trees.instance(task);
1507
1508            final DPrinter dprinter = new DPrinter(out, trees);
1509            dprinter.source(showSource)
1510                    .emptyItems(showEmptyItems)
1511                    .nulls(showNulls)
1512                    .positions(showPositions)
1513                    .treeSymbols(showTreeSymbols)
1514                    .treeTypes(showTreeTypes);
1515
1516            if (before.isEmpty() && after.isEmpty()) {
1517                if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
1518                    after.add(TaskEvent.Kind.PARSE);
1519                else
1520                    after.add(TaskEvent.Kind.ANALYZE);
1521            }
1522
1523            task.addTaskListener(new TaskListener() {
1524                public void started(TaskEvent e) {
1525                    if (before.contains(e.getKind()))
1526                        handle(e);
1527                }
1528
1529                public void finished(TaskEvent e) {
1530                    if (after.contains(e.getKind()))
1531                        handle(e);
1532                }
1533
1534                private void handle(TaskEvent e) {
1535                    JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
1536                     switch (e.getKind()) {
1537                         case PARSE:
1538                         case ENTER:
1539                             h.handle(e.getSourceFile().getName(),
1540                                     unit, unit,
1541                                     dprinter);
1542                             break;
1543
1544                         default:
1545                             TypeElement elem = e.getTypeElement();
1546                             h.handle(elem.toString(),
1547                                     unit, (JCTree) trees.getTree(elem),
1548                                     dprinter);
1549                             break;
1550                     }
1551                }
1552            });
1553
1554            task.call();
1555        }
1556
1557        TaskEvent.Kind getKind(String s) {
1558            return TaskEvent.Kind.valueOf(s.toUpperCase());
1559        }
1560
1561        static protected abstract class Handler {
1562            final String name;
1563            Handler(String name) {
1564                this.name = name;
1565            }
1566            abstract void handle(String label,
1567                    JCCompilationUnit unit, JCTree tree,
1568                    DPrinter dprinter);
1569        }
1570
1571        Map<String,Handler> getHandlers() {
1572            Map<String,Handler> map = new HashMap<String, Handler>();
1573            for (Handler h: defaultHandlers) {
1574                map.put(h.name, h);
1575            }
1576            return map;
1577        }
1578
1579        protected final Handler[] defaultHandlers = {
1580            new Handler("trees") {
1581                @Override
1582                void handle(String name, JCCompilationUnit unit, JCTree tree, DPrinter dprinter) {
1583                    dprinter.printTree(name, tree);
1584                    dprinter.out.println();
1585                }
1586            },
1587
1588            new Handler("doctrees") {
1589                @Override
1590                void handle(final String name, final JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1591                    TreeScanner ds = new DeclScanner() {
1592                        public void visitDecl(JCTree tree, Symbol sym) {
1593                            DocTree dt = unit.docComments.getCommentTree(tree);
1594                            if (dt != null) {
1595                                String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1596                                dprinter.printDocTree(label, dt);
1597                                dprinter.out.println();
1598                            }
1599                        }
1600                    };
1601                    ds.scan(tree);
1602                }
1603            },
1604
1605            new Handler("symbols") {
1606                @Override
1607                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1608                    TreeScanner ds = new DeclScanner() {
1609                        public void visitDecl(JCTree tree, Symbol sym) {
1610                            String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1611                            dprinter.printSymbol(label, sym);
1612                            dprinter.out.println();
1613                        }
1614                    };
1615                    ds.scan(tree);
1616                }
1617            },
1618
1619            new Handler("types") {
1620                @Override
1621                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1622                    TreeScanner ts = new TreeScanner() {
1623                        @Override
1624                        public void scan(JCTree tree) {
1625                            if (tree == null) {
1626                                return;
1627                            }
1628                            if (tree.type != null) {
1629                                String label = Pretty.toSimpleString(tree);
1630                                dprinter.printType(label, tree.type);
1631                                dprinter.out.println();
1632                            }
1633                            super.scan(tree);
1634                        }
1635                    };
1636                    ts.scan(tree);
1637                }
1638            }
1639        };
1640    }
1641
1642    protected static abstract class DeclScanner extends TreeScanner {
1643        @Override
1644        public void visitClassDef(JCClassDecl tree) {
1645            visitDecl(tree, tree.sym);
1646            super.visitClassDef(tree);
1647        }
1648
1649        @Override
1650        public void visitMethodDef(JCMethodDecl tree) {
1651            visitDecl(tree, tree.sym);
1652            super.visitMethodDef(tree);
1653        }
1654
1655        @Override
1656        public void visitVarDef(JCVariableDecl tree) {
1657            visitDecl(tree, tree.sym);
1658            super.visitVarDef(tree);
1659        }
1660
1661        protected abstract void visitDecl(JCTree tree, Symbol sym);
1662    }
1663
1664    // </editor-fold>
1665
1666}
1667