DPrinter.java revision 3162:f164d4c2d33e
1251876Speter/*
2251876Speter * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
3251876Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4251876Speter *
5251876Speter * This code is free software; you can redistribute it and/or modify it
6251876Speter * under the terms of the GNU General Public License version 2 only, as
7251876Speter * published by the Free Software Foundation.
8251876Speter *
9251876Speter * This code is distributed in the hope that it will be useful, but WITHOUT
10251876Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11251876Speter * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12251876Speter * version 2 for more details (a copy is included in the LICENSE file that
13251876Speter * accompanied this code).
14251876Speter *
15251876Speter * You should have received a copy of the GNU General Public License version
16251876Speter * 2 along with this work; if not, write to the Free Software Foundation,
17251876Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18251876Speter *
19251876Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20251876Speter * or visit www.oracle.com if you need additional information or have any
21251876Speter * questions.
22251876Speter */
23251876Speter
24251876Speter/* @test
25251876Speter * @bug 8043484 8007307
26251876Speter * @summary Make sure DPrinter.java compiles
27251876Speter * @modules jdk.compiler/com.sun.tools.javac.api
28251876Speter *          jdk.compiler/com.sun.tools.javac.code
29251876Speter *          jdk.compiler/com.sun.tools.javac.tree
30251876Speter *          jdk.compiler/com.sun.tools.javac.util
31251876Speter * @compile DPrinter.java
32251876Speter */
33251876Speter
34251876Speterimport java.io.File;
35251876Speterimport java.io.IOException;
36251876Speterimport java.io.PrintWriter;
37251876Speterimport java.lang.reflect.Field;
38251876Speterimport java.lang.reflect.Method;
39251876Speterimport java.util.ArrayList;
40251876Speterimport java.util.Arrays;
41251876Speterimport java.util.Collection;
42251876Speterimport java.util.EnumSet;
43251876Speterimport java.util.HashMap;
44251876Speterimport java.util.List;
45251876Speterimport java.util.Locale;
46251876Speterimport java.util.Map;
47251876Speterimport java.util.Set;
48251876Speter
49251876Speterimport javax.lang.model.element.Name;
50251876Speterimport javax.lang.model.element.TypeElement;
51251876Speterimport javax.tools.FileObject;
52251876Speterimport javax.tools.JavaCompiler;
53251876Speterimport javax.tools.JavaFileObject;
54251876Speterimport javax.tools.StandardJavaFileManager;
55251876Speterimport javax.tools.StandardLocation;
56251876Speterimport javax.tools.ToolProvider;
57251876Speter
58251876Speterimport com.sun.source.doctree.*;
59251876Speterimport com.sun.source.util.JavacTask;
60251876Speterimport com.sun.source.util.TaskEvent;
61251876Speterimport com.sun.source.util.TaskListener;
62251876Speterimport com.sun.source.util.Trees;
63251876Speterimport com.sun.tools.javac.api.JavacTrees;
64251876Speterimport com.sun.tools.javac.code.SymbolMetadata;
65251876Speterimport com.sun.tools.javac.code.Attribute;
66251876Speterimport com.sun.tools.javac.code.Flags;
67251876Speterimport com.sun.tools.javac.code.Kinds;
68251876Speterimport com.sun.tools.javac.code.Printer;
69251876Speterimport com.sun.tools.javac.code.Scope;
70251876Speterimport com.sun.tools.javac.code.Scope.CompoundScope;
71251876Speterimport com.sun.tools.javac.code.Symbol;
72251876Speterimport com.sun.tools.javac.code.Symbol.*;
73251876Speterimport com.sun.tools.javac.code.Type;
74251876Speterimport com.sun.tools.javac.code.Type.*;
75251876Speterimport com.sun.tools.javac.code.TypeTag;
76251876Speterimport com.sun.tools.javac.tree.JCTree;
77251876Speterimport com.sun.tools.javac.tree.JCTree.*;
78251876Speterimport com.sun.tools.javac.tree.Pretty;
79251876Speterimport com.sun.tools.javac.tree.TreeInfo;
80251876Speterimport com.sun.tools.javac.tree.TreeScanner;
81251876Speterimport com.sun.tools.javac.util.Assert;
82251876Speterimport com.sun.tools.javac.util.Context;
83251876Speterimport com.sun.tools.javac.util.Convert;
84251876Speterimport com.sun.tools.javac.util.Log;
85251876Speter
86251876Speter
87251876Speter/**
88251876Speter * Debug printer for javac internals, for when toString() just isn't enough.
89251876Speter *
90251876Speter * <p>
91251876Speter * The printer provides an API to generate structured views of javac objects,
92251876Speter * such as AST nodes, symbol, types and annotations. Various aspects of the
93251876Speter * output can be configured, such as whether to show nulls, empty lists, or
94251876Speter * a compressed representation of the source code. Visitors are used to walk
95251876Speter * object hierarchies, and can be replaced with custom visitors if the default
96251876Speter * visitors are not flexible enough.
97251876Speter *
98251876Speter * <p>
99251876Speter * In general, nodes are printed with an initial line identifying the node
100251876Speter * followed by indented lines for the child nodes. Currently, graphs are
101251876Speter * represented by printing a spanning subtree.
102251876Speter *
103251876Speter * <p>
104251876Speter * The printer can be accessed via a simple command-line utility,
105251876Speter * which makes it easy to see the internal representation of source code,
106251876Speter * such as simple test programs, during the compilation pipeline.
107251876Speter *
108251876Speter *  <p><b>This is NOT part of any supported API.
109251876Speter *  If you write code that depends on this, you do so at your own risk.
110251876Speter *  This code and its internal interfaces are subject to change or
111251876Speter *  deletion without notice.</b>
112251876Speter */
113251876Speter
114251876Speterpublic class DPrinter {
115251876Speter    protected final PrintWriter out;
116251876Speter    protected final Trees trees;
117251876Speter    protected Printer printer;
118251876Speter    protected boolean showEmptyItems = true;
119251876Speter    protected boolean showNulls = true;
120251876Speter    protected boolean showPositions = false;
121251876Speter    protected boolean showSrc;
122251876Speter    protected boolean showTreeSymbols;
123251876Speter    protected boolean showTreeTypes;
124251876Speter    protected int maxSrcLength = 32;
125251876Speter    protected Locale locale = Locale.getDefault();
126251876Speter    protected static final String NULL = "#null";
127251876Speter
128251876Speter    // <editor-fold defaultstate="collapsed" desc="Configuration">
129251876Speter
130251876Speter    public static DPrinter instance(Context context) {
131251876Speter        DPrinter dp = context.get(DPrinter.class);
132251876Speter        if (dp == null) {
133251876Speter            dp = new DPrinter(context);
134251876Speter        }
135251876Speter        return dp;
136251876Speter
137251876Speter    }
138251876Speter
139251876Speter    protected DPrinter(Context context) {
140251876Speter        context.put(DPrinter.class, this);
141251876Speter        out = context.get(Log.outKey);
142251876Speter        trees = JavacTrees.instance(context);
143251876Speter    }
144251876Speter
145251876Speter    public DPrinter(PrintWriter out, Trees trees) {
146251876Speter        this.out = out;
147251876Speter        this.trees = trees;
148251876Speter    }
149251876Speter
150251876Speter    public DPrinter emptyItems(boolean showEmptyItems) {
151251876Speter        this.showEmptyItems = showEmptyItems;
152251876Speter        return this;
153251876Speter    }
154251876Speter
155251876Speter    public DPrinter nulls(boolean showNulls) {
156251876Speter        this.showNulls = showNulls;
157251876Speter        return this;
158251876Speter    }
159251876Speter
160251876Speter    public DPrinter positions(boolean showPositions) {
161251876Speter        this.showPositions = showPositions;
162251876Speter        return this;
163251876Speter    }
164251876Speter
165251876Speter    public DPrinter source(boolean showSrc) {
166251876Speter        this.showSrc = showSrc;
167251876Speter        return this;
168251876Speter    }
169251876Speter
170251876Speter    public DPrinter source(int maxSrcLength) {
171251876Speter        this.showSrc = true;
172251876Speter        this.maxSrcLength = maxSrcLength;
173251876Speter        return this;
174251876Speter    }
175251876Speter
176251876Speter    public DPrinter treeSymbols(boolean showTreeSymbols) {
177251876Speter        this.showTreeSymbols = showTreeSymbols;
178251876Speter        return this;
179251876Speter    }
180251876Speter
181251876Speter    public DPrinter treeTypes(boolean showTreeTypes) {
182251876Speter        this.showTreeTypes = showTreeTypes;
183251876Speter        return this;
184251876Speter    }
185251876Speter
186251876Speter    public DPrinter typeSymbolPrinter(Printer p) {
187251876Speter        printer = p;
188251876Speter        return this;
189251876Speter    }
190251876Speter
191251876Speter    // </editor-fold>
192251876Speter
193251876Speter    // <editor-fold defaultstate="collapsed" desc="Printing">
194251876Speter
195251876Speter    protected enum Details {
196251876Speter        /** A one-line non-recursive summary */
197251876Speter        SUMMARY,
198251876Speter        /** Multi-line, possibly recursive. */
199251876Speter        FULL
200251876Speter    };
201251876Speter
202251876Speter    public void printAnnotations(String label, SymbolMetadata annotations) {
203251876Speter        printAnnotations(label, annotations, Details.FULL);
204251876Speter    }
205251876Speter
206251876Speter    protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
207251876Speter        if (annotations == null) {
208251876Speter            printNull(label);
209251876Speter        } else {
210251876Speter            // no SUMMARY format currently available to use
211251876Speter
212251876Speter            // use reflection to get at private fields
213251876Speter            Object DECL_NOT_STARTED = getField(null, SymbolMetadata.class, "DECL_NOT_STARTED");
214251876Speter            Object DECL_IN_PROGRESS = getField(null, SymbolMetadata.class, "DECL_IN_PROGRESS");
215251876Speter            Object attributes = getField(annotations, SymbolMetadata.class, "attributes");
216251876Speter            Object type_attributes = getField(annotations, SymbolMetadata.class, "type_attributes");
217251876Speter
218251876Speter            if (!showEmptyItems) {
219251876Speter                if (attributes instanceof List && ((List) attributes).isEmpty()
220251876Speter                        && attributes != DECL_NOT_STARTED
221251876Speter                        && attributes != DECL_IN_PROGRESS
222251876Speter                        && type_attributes instanceof List && ((List) type_attributes).isEmpty())
223251876Speter                    return;
224251876Speter            }
225251876Speter
226251876Speter            printString(label, hashString(annotations));
227251876Speter
228251876Speter            indent(+1);
229251876Speter            if (attributes == DECL_NOT_STARTED)
230251876Speter                printString("attributes", "DECL_NOT_STARTED");
231251876Speter            else if (attributes == DECL_IN_PROGRESS)
232251876Speter                printString("attributes", "DECL_IN_PROGRESS");
233251876Speter            else if (attributes instanceof List)
234251876Speter                printList("attributes", (List) attributes);
235251876Speter            else
236251876Speter                printObject("attributes", attributes, Details.SUMMARY);
237251876Speter
238251876Speter            if (attributes instanceof List)
239251876Speter                printList("type_attributes", (List) type_attributes);
240251876Speter            else
241251876Speter                printObject("type_attributes", type_attributes, Details.SUMMARY);
242251876Speter            indent(-1);
243251876Speter        }
244251876Speter    }
245251876Speter
246251876Speter    public void printAttribute(String label, Attribute attr) {
247251876Speter        if (attr == null) {
248251876Speter            printNull(label);
249251876Speter        } else {
250251876Speter            printString(label, attr.getClass().getSimpleName());
251251876Speter
252251876Speter            indent(+1);
253251876Speter            attr.accept(attrVisitor);
254251876Speter            indent(-1);
255251876Speter        }
256251876Speter    }
257251876Speter
258251876Speter    public void printDocTree(String label, DocTree tree) {
259251876Speter        if (tree == null) {
260251876Speter             printNull(label);
261251876Speter        } else {
262251876Speter            indent();
263251876Speter            out.print(label);
264251876Speter            out.println(": " + tree.getClass().getSimpleName() + "," + tree.getKind());
265251876Speter
266251876Speter            indent(+1);
267251876Speter            tree.accept(docTreeVisitor, null);
268251876Speter            indent(-1);
269251876Speter        }
270251876Speter    }
271251876Speter
272251876Speter    public void printFileObject(String label, FileObject fo) {
273251876Speter        if (fo == null) {
274251876Speter            printNull(label);
275251876Speter        } else {
276251876Speter            printString(label, fo.getName());
277251876Speter        }
278251876Speter    }
279251876Speter
280251876Speter    protected <T> void printImplClass(T item, Class<? extends T> stdImplClass) {
281251876Speter        if (item.getClass() != stdImplClass)
282251876Speter            printString("impl", item.getClass().getName());
283251876Speter    }
284251876Speter
285251876Speter    public void printInt(String label, int i) {
286251876Speter        printString(label, String.valueOf(i));
287251876Speter    }
288251876Speter
289251876Speter    public void printLimitedEscapedString(String label, String text) {
290251876Speter        String s = Convert.quote(text);
291251876Speter        if (s.length() > maxSrcLength) {
292251876Speter            String trim = "[...]";
293251876Speter            int head = (maxSrcLength - trim.length()) * 2 / 3;
294251876Speter            int tail = maxSrcLength - trim.length() - head;
295251876Speter            s = s.substring(0, head) + trim + s.substring(s.length() - tail);
296251876Speter        }
297251876Speter        printString(label, s);
298251876Speter    }
299251876Speter
300251876Speter    public void printList(String label, List<?> list) {
301251876Speter        if (list == null) {
302251876Speter             printNull(label);
303251876Speter        } else if (!list.isEmpty() || showEmptyItems) {
304251876Speter            printString(label, "[" + list.size() + "]");
305251876Speter
306251876Speter            indent(+1);
307251876Speter            int i = 0;
308251876Speter            for (Object item: list) {
309251876Speter                printObject(String.valueOf(i++), item, Details.FULL);
310251876Speter            }
311251876Speter            indent(-1);
312251876Speter        }
313251876Speter    }
314251876Speter
315251876Speter    public void printName(String label, Name name) {
316262253Speter        if (name == null) {
317251876Speter            printNull(label);
318251876Speter        } else {
319251876Speter            printString(label, name.toString());
320251876Speter        }
321262253Speter    }
322251876Speter
323251876Speter    public void printNull(String label) {
324251876Speter        if (showNulls)
325251876Speter            printString(label, NULL);
326262253Speter    }
327251876Speter
328251876Speter    protected void printObject(String label, Object item, Details details) {
329251876Speter        if (item == null) {
330251876Speter            printNull(label);
331251876Speter        } else if (item instanceof Attribute) {
332251876Speter            printAttribute(label, (Attribute) item);
333262253Speter        } else if (item instanceof Symbol) {
334251876Speter            printSymbol(label, (Symbol) item, details);
335251876Speter        } else if (item instanceof Type) {
336251876Speter            printType(label, (Type) item, details);
337251876Speter        } else if (item instanceof JCTree) {
338251876Speter            printTree(label, (JCTree) item);
339251876Speter        } else if (item instanceof DocTree) {
340251876Speter            printDocTree(label, (DocTree) item);
341251876Speter        } else if (item instanceof List) {
342251876Speter            printList(label, (List) item);
343251876Speter        } else if (item instanceof Name) {
344251876Speter            printName(label, (Name) item);
345251876Speter        } else if (item instanceof Scope) {
346251876Speter            printScope(label, (Scope) item);
347251876Speter        } else {
348251876Speter            printString(label, String.valueOf(item));
349251876Speter        }
350251876Speter    }
351251876Speter
352251876Speter    public void printScope(String label, Scope scope) {
353251876Speter        printScope(label, scope, Details.FULL);
354251876Speter    }
355251876Speter
356251876Speter    public void printScope(String label, Scope scope, Details details) {
357251876Speter        if (scope == null) {
358251876Speter            printNull(label);
359        } else {
360            switch (details) {
361                case SUMMARY: {
362                    indent();
363                    out.print(label);
364                    out.print(": [");
365                    String sep = "";
366                    for (Symbol sym: scope.getSymbols()) {
367                        out.print(sep);
368                        out.print(sym.name);
369                        sep = ",";
370                    }
371                    out.println("]");
372                    break;
373                }
374
375                case FULL: {
376                    indent();
377                    out.println(label);
378
379                    indent(+1);
380                    printFullScopeImpl(scope);
381                    indent(-1);
382                    break;
383                }
384            }
385        }
386    }
387
388    void printFullScopeImpl(Scope scope) {
389        indent();
390        out.println(scope.getClass().getName());
391        printSymbol("owner", scope.owner, Details.SUMMARY);
392        if (SCOPE_IMPL_CLASS.equals(scope.getClass().getName())) {
393            printScope("next", (Scope) getField(scope, scope.getClass(), "next"), Details.SUMMARY);
394            printObject("shared", getField(scope, scope.getClass(), "shared"), Details.SUMMARY);
395            Object[] table = (Object[]) getField(scope, scope.getClass(), "table");
396            for (int i = 0; i < table.length; i++) {
397                if (i > 0)
398                    out.print(", ");
399                else
400                    indent();
401                out.print(i + ":" + entryToString(table[i], table, false));
402            }
403            out.println();
404        } else if (FILTER_SCOPE_CLASS.equals(scope.getClass().getName())) {
405            printScope("origin",
406                    (Scope) getField(scope, scope.getClass(), "origin"), Details.FULL);
407        } else if (scope instanceof CompoundScope) {
408            printList("delegates", (List<?>) getField(scope, CompoundScope.class, "subScopes"));
409        } else {
410            for (Symbol sym : scope.getSymbols()) {
411                printSymbol(sym.name.toString(), sym, Details.SUMMARY);
412            }
413        }
414    }
415        //where:
416        static final String SCOPE_IMPL_CLASS = "com.sun.tools.javac.code.Scope$ScopeImpl";
417        static final String FILTER_SCOPE_CLASS = "com.sun.tools.javac.code.Scope$FilterImportScope";
418
419    /**
420     * Create a string showing the contents of an entry, using the table
421     * to help identify cross-references to other entries in the table.
422     * @param e the entry to be shown
423     * @param table the table containing the other entries
424     */
425    String entryToString(Object e, Object[] table, boolean ref) {
426        if (e == null)
427            return "null";
428        Symbol sym = (Symbol) getField(e, e.getClass(), "sym");
429        if (sym == null)
430            return "sent"; // sentinel
431        if (ref) {
432            int index = indexOf(table, e);
433            if (index != -1)
434                return String.valueOf(index);
435        }
436        Scope scope = (Scope) getField(e, e.getClass(), "scope");
437        return "(" + sym.name + ":" + sym
438                + ",shdw:" + entryToString(callMethod(e, e.getClass(), "next"), table, true)
439                + ",sibl:" + entryToString(getField(e, e.getClass(), "sibling"), table, true)
440                + ((sym.owner != scope.owner)
441                    ? (",BOGUS[" + sym.owner + "," + scope.owner + "]")
442                    : "")
443                + ")";
444    }
445
446    <T> int indexOf(T[] array, T item) {
447        for (int i = 0; i < array.length; i++) {
448            if (array[i] == item)
449                return i;
450        }
451        return -1;
452    }
453
454    public void printSource(String label, JCTree tree) {
455        printString(label, Pretty.toSimpleString(tree, maxSrcLength));
456    }
457
458    public void printString(String label, String text) {
459        indent();
460        out.print(label);
461        out.print(": ");
462        out.print(text);
463        out.println();
464    }
465
466    public void printSymbol(String label, Symbol symbol) {
467        printSymbol(label, symbol, Details.FULL);
468    }
469
470    protected void printSymbol(String label, Symbol sym, Details details) {
471        if (sym == null) {
472            printNull(label);
473        } else {
474            switch (details) {
475            case SUMMARY:
476                printString(label, toString(sym));
477                break;
478
479            case FULL:
480                indent();
481                out.print(label);
482                out.println(": " +
483                        info(sym.getClass(),
484                            String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
485                            sym.getKind())
486                        + " " + sym.name
487                        + " " + hashString(sym));
488
489                indent(+1);
490                if (showSrc) {
491                    JCTree tree = (JCTree) trees.getTree(sym);
492                    if (tree != null)
493                        printSource("src", tree);
494                }
495                printString("flags", String.format("0x%x--%s",
496                        sym.flags_field, Flags.toString(sym.flags_field)));
497                printObject("completer", sym.completer, Details.SUMMARY); // what if too long?
498                printSymbol("owner", sym.owner, Details.SUMMARY);
499                printType("type", sym.type, Details.SUMMARY);
500                printType("erasure", sym.erasure_field, Details.SUMMARY);
501                sym.accept(symVisitor, null);
502                printAnnotations("annotations", sym.getMetadata(), Details.SUMMARY);
503                indent(-1);
504            }
505        }
506    }
507
508    protected String toString(Symbol sym) {
509        return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym);
510    }
511
512    protected void printTree(String label, JCTree tree) {
513        if (tree == null) {
514            printNull(label);
515        } else {
516            indent();
517            String ext;
518            try {
519                ext = tree.getKind().name();
520            } catch (Throwable t) {
521                ext = "n/a";
522            }
523            out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext));
524            if (showPositions) {
525                // We can always get start position, but to get end position
526                // and/or line+offset, we would need a JCCompilationUnit
527                out.print(" pos:" + tree.pos);
528            }
529            if (showTreeTypes && tree.type != null)
530                out.print(" type:" + toString(tree.type));
531            Symbol sym;
532            if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null)
533                out.print(" sym:" + toString(sym));
534            out.println();
535
536            indent(+1);
537            if (showSrc) {
538                indent();
539                out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength));
540            }
541            tree.accept(treeVisitor);
542            indent(-1);
543        }
544    }
545
546    public void printType(String label, Type type) {
547        printType(label, type, Details.FULL);
548    }
549
550    protected void printType(String label, Type type, Details details) {
551        if (type == null)
552            printNull(label);
553        else {
554            switch (details) {
555                case SUMMARY:
556                    printString(label, toString(type));
557                    break;
558
559                case FULL:
560                    indent();
561                    out.print(label);
562                    out.println(": " + info(type.getClass(), type.getTag(), type.getKind())
563                            + " " + hashString(type));
564
565                    indent(+1);
566                    printSymbol("tsym", type.tsym, Details.SUMMARY);
567                    printObject("constValue", type.constValue(), Details.SUMMARY);
568                    printObject("annotations", type.getAnnotationMirrors(), Details.SUMMARY);
569                    type.accept(typeVisitor, null);
570                    indent(-1);
571            }
572        }
573    }
574
575    protected String toString(Type type) {
576        return (printer != null) ? printer.visit(type, locale) : String.valueOf(type);
577    }
578
579    protected String hashString(Object obj) {
580        return String.format("#%x", obj.hashCode());
581    }
582
583    protected String info(Class<?> clazz, Object internal, Object external) {
584        return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external);
585    }
586
587    private int indent = 0;
588
589    protected void indent() {
590        for (int i = 0; i < indent; i++) {
591            out.print("  ");
592        }
593    }
594
595    protected void indent(int n) {
596        indent += n;
597    }
598
599    protected Object getField(Object o, Class<?> clazz, String name) {
600        try {
601            Field f = clazz.getDeclaredField(name);
602            boolean prev = f.isAccessible();
603            f.setAccessible(true);
604            try {
605                return f.get(o);
606            } finally {
607                f.setAccessible(prev);
608            }
609        } catch (ReflectiveOperationException e) {
610            return e;
611        } catch (SecurityException e) {
612            return e;
613        }
614    }
615
616    protected Object callMethod(Object o, Class<?> clazz, String name) {
617        try {
618            Method m = clazz.getDeclaredMethod(name);
619            boolean prev = m.isAccessible();
620            m.setAccessible(true);
621            try {
622                return m.invoke(o);
623            } finally {
624                m.setAccessible(prev);
625            }
626        } catch (ReflectiveOperationException e) {
627            return e;
628        } catch (SecurityException e) {
629            return e;
630        }
631    }
632
633    // </editor-fold>
634
635    // <editor-fold defaultstate="collapsed" desc="JCTree visitor methods">
636
637    protected JCTree.Visitor treeVisitor = new TreeVisitor();
638
639    /**
640     * Default visitor class for JCTree (AST) objects.
641     */
642    public class TreeVisitor extends JCTree.Visitor {
643        @Override
644        public void visitTopLevel(JCCompilationUnit tree) {
645            printList("packageAnnotations", tree.getPackageAnnotations());
646            printList("defs", tree.defs);
647        }
648
649        @Override
650        public void visitPackageDef(JCPackageDecl tree) {
651            printTree("pid", tree.pid);
652        }
653
654        @Override
655        public void visitImport(JCImport tree) {
656            printTree("qualid", tree.qualid);
657        }
658
659        @Override
660        public void visitClassDef(JCClassDecl tree) {
661            printName("name", tree.name);
662            printTree("mods", tree.mods);
663            printList("typarams", tree.typarams);
664            printTree("extending", tree.extending);
665            printList("implementing", tree.implementing);
666            printList("defs", tree.defs);
667        }
668
669        @Override
670        public void visitMethodDef(JCMethodDecl tree) {
671            printName("name", tree.name);
672            printTree("mods", tree.mods);
673            printTree("restype", tree.restype);
674            printList("typarams", tree.typarams);
675            printTree("recvparam", tree.recvparam);
676            printList("params", tree.params);
677            printList("thrown", tree.thrown);
678            printTree("defaultValue", tree.defaultValue);
679            printTree("body", tree.body);
680        }
681
682        @Override
683        public void visitVarDef(JCVariableDecl tree) {
684            printName("name", tree.name);
685            printTree("mods", tree.mods);
686            printTree("vartype", tree.vartype);
687            printTree("init", tree.init);
688        }
689
690        @Override
691        public void visitSkip(JCSkip tree) {
692        }
693
694        @Override
695        public void visitBlock(JCBlock tree) {
696            printList("stats", tree.stats);
697        }
698
699        @Override
700        public void visitDoLoop(JCDoWhileLoop tree) {
701            printTree("body", tree.body);
702            printTree("cond", tree.cond);
703        }
704
705        @Override
706        public void visitWhileLoop(JCWhileLoop tree) {
707            printTree("cond", tree.cond);
708            printTree("body", tree.body);
709        }
710
711        @Override
712        public void visitForLoop(JCForLoop tree) {
713            printList("init", tree.init);
714            printTree("cond", tree.cond);
715            printList("step", tree.step);
716            printTree("body", tree.body);
717        }
718
719        @Override
720        public void visitForeachLoop(JCEnhancedForLoop tree) {
721            printTree("var", tree.var);
722            printTree("expr", tree.expr);
723            printTree("body", tree.body);
724        }
725
726        @Override
727        public void visitLabelled(JCLabeledStatement tree) {
728            printTree("body", tree.body);
729        }
730
731        @Override
732        public void visitSwitch(JCSwitch tree) {
733            printTree("selector", tree.selector);
734            printList("cases", tree.cases);
735        }
736
737        @Override
738        public void visitCase(JCCase tree) {
739            printTree("pat", tree.pat);
740            printList("stats", tree.stats);
741        }
742
743        @Override
744        public void visitSynchronized(JCSynchronized tree) {
745            printTree("lock", tree.lock);
746            printTree("body", tree.body);
747        }
748
749        @Override
750        public void visitTry(JCTry tree) {
751            printList("resources", tree.resources);
752            printTree("body", tree.body);
753            printList("catchers", tree.catchers);
754            printTree("finalizer", tree.finalizer);
755        }
756
757        @Override
758        public void visitCatch(JCCatch tree) {
759            printTree("param", tree.param);
760            printTree("body", tree.body);
761        }
762
763        @Override
764        public void visitConditional(JCConditional tree) {
765            printTree("cond", tree.cond);
766            printTree("truepart", tree.truepart);
767            printTree("falsepart", tree.falsepart);
768        }
769
770        @Override
771        public void visitIf(JCIf tree) {
772            printTree("cond", tree.cond);
773            printTree("thenpart", tree.thenpart);
774            printTree("elsepart", tree.elsepart);
775        }
776
777        @Override
778        public void visitExec(JCExpressionStatement tree) {
779            printTree("expr", tree.expr);
780        }
781
782        @Override
783        public void visitBreak(JCBreak tree) {
784            printName("label", tree.label);
785        }
786
787        @Override
788        public void visitContinue(JCContinue tree) {
789            printName("label", tree.label);
790        }
791
792        @Override
793        public void visitReturn(JCReturn tree) {
794            printTree("expr", tree.expr);
795        }
796
797        @Override
798        public void visitThrow(JCThrow tree) {
799            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 visitPackageType(PackageType type, Void ignore) {
1296            return visitType(type, null);
1297        }
1298
1299        public Void visitTypeVar(TypeVar type, Void ignore) {
1300            // For TypeVars (and not subtypes), the bound should always be
1301            // null or bot. So, only print the bound for subtypes of TypeVar,
1302            // or if the bound is (erroneously) not null or bot.
1303            if (!type.hasTag(TypeTag.TYPEVAR)
1304                    || !(type.bound == null || type.bound.hasTag(TypeTag.BOT))) {
1305                printType("bound", type.bound, Details.FULL);
1306            }
1307            printType("lower", type.lower, Details.FULL);
1308            return visitType(type, null);
1309        }
1310
1311        public Void visitUndetVar(UndetVar type, Void ignore) {
1312            for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
1313                printList("bounds." + ib, type.getBounds(ib));
1314            printInt("declaredCount", type.declaredCount);
1315            printType("inst", type.getInst(), Details.SUMMARY);
1316            return visitDelegatedType(type);
1317        }
1318
1319        public Void visitWildcardType(WildcardType type, Void ignore) {
1320            printType("type", type.type, Details.SUMMARY);
1321            printString("kind", type.kind.name());
1322            printType("bound", type.bound, Details.SUMMARY);
1323            return visitType(type, null);
1324        }
1325
1326        protected Void visitDelegatedType(DelegatedType type) {
1327            printType("qtype", type.qtype, Details.FULL);
1328            return visitType(type, null);
1329        }
1330
1331        public Void visitType(Type type, Void ignore) {
1332            return null;
1333        }
1334    }
1335
1336    // </editor-fold>
1337
1338    // <editor-fold defaultstate="collapsed" desc="Attribute (annotations) visitor">
1339
1340    protected Attribute.Visitor attrVisitor = new AttributeVisitor();
1341
1342    /**
1343     * Default visitor class for Attribute (annotation) objects.
1344     */
1345    public class AttributeVisitor implements Attribute.Visitor {
1346
1347        public void visitConstant(Attribute.Constant a) {
1348            printObject("value", a.value, Details.SUMMARY);
1349            visitAttribute(a);
1350        }
1351
1352        public void visitClass(Attribute.Class a) {
1353            printObject("classType", a.classType, Details.SUMMARY);
1354            visitAttribute(a);
1355        }
1356
1357        public void visitCompound(Attribute.Compound a) {
1358            if (a instanceof Attribute.TypeCompound) {
1359                Attribute.TypeCompound ta = (Attribute.TypeCompound) a;
1360                // consider a custom printer?
1361                printObject("position", ta.position, Details.SUMMARY);
1362            }
1363            printObject("synthesized", a.isSynthesized(), Details.SUMMARY);
1364            printList("values", a.values);
1365            visitAttribute(a);
1366        }
1367
1368        public void visitArray(Attribute.Array a) {
1369            printList("values", Arrays.asList(a.values));
1370            visitAttribute(a);
1371        }
1372
1373        public void visitEnum(Attribute.Enum a) {
1374            printSymbol("value", a.value, Details.SUMMARY);
1375            visitAttribute(a);
1376        }
1377
1378        public void visitError(Attribute.Error a) {
1379            visitAttribute(a);
1380        }
1381
1382        public void visitAttribute(Attribute a) {
1383            printType("type", a.type, Details.SUMMARY);
1384        }
1385
1386    }
1387    // </editor-fold>
1388
1389    // <editor-fold defaultstate="collapsed" desc="Utility front end">
1390
1391    /**
1392     * Utility class to invoke DPrinter from the command line.
1393     */
1394    static class Main {
1395        public static void main(String... args) throws IOException {
1396            Main m = new Main();
1397            PrintWriter out = new PrintWriter(System.out);
1398            try {
1399                if (args.length == 0)
1400                    m.usage(out);
1401                else
1402                    m.run(out, args);
1403            } finally {
1404                out.flush();
1405            }
1406        }
1407
1408        void usage(PrintWriter out) {
1409            out.println("Usage:");
1410            out.println("  java " + Main.class.getName() + " mode [options] [javac-options]");
1411            out.print("where mode is one of: ");
1412            String sep = "";
1413            for (Handler h: getHandlers().values()) {
1414                out.print(sep);
1415                out.print(h.name);
1416                sep = ", ";
1417            }
1418            out.println();
1419            out.println("and where options include:");
1420            out.println("  -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1421            out.println("  -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND");
1422            out.println("  -showPositions");
1423            out.println("  -showSource");
1424            out.println("  -showTreeSymbols");
1425            out.println("  -showTreeTypes");
1426            out.println("  -hideEmptyItems");
1427            out.println("  -hideNulls");
1428        }
1429
1430        void run(PrintWriter out, String... args) throws IOException {
1431            JavaCompiler c = ToolProvider.getSystemJavaCompiler();
1432            StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
1433
1434            // DPrinter options
1435            final Set<TaskEvent.Kind> before = EnumSet.noneOf(TaskEvent.Kind.class);
1436            final Set<TaskEvent.Kind> after = EnumSet.noneOf(TaskEvent.Kind.class);
1437            boolean showPositions = false;
1438            boolean showSource = false;
1439            boolean showTreeSymbols = false;
1440            boolean showTreeTypes = false;
1441            boolean showEmptyItems = true;
1442            boolean showNulls = true;
1443
1444            // javac options
1445            Collection<String> options = new ArrayList<String>();
1446            Collection<File> files = new ArrayList<File>();
1447            String classpath = null;
1448            String classoutdir = null;
1449
1450            final Handler h = getHandlers().get(args[0]);
1451            if (h == null)
1452                throw new IllegalArgumentException(args[0]);
1453
1454            for (int i = 1; i < args.length; i++) {
1455                String arg = args[i];
1456                if (arg.equals("-before") && i + 1 < args.length) {
1457                    before.add(getKind(args[++i]));
1458                } else if (arg.equals("-after") && i + 1 < args.length) {
1459                    after.add(getKind(args[++i]));
1460                } else if (arg.equals("-showPositions")) {
1461                    showPositions = true;
1462                } else if (arg.equals("-showSource")) {
1463                    showSource = true;
1464                } else if (arg.equals("-showTreeSymbols")) {
1465                    showTreeSymbols = true;
1466                } else if (arg.equals("-showTreeTypes")) {
1467                    showTreeTypes = true;
1468                } else if (arg.equals("-hideEmptyLists")) {
1469                    showEmptyItems = false;
1470                } else if (arg.equals("-hideNulls")) {
1471                    showNulls = false;
1472                } else if (arg.equals("-classpath") && i + 1 < args.length) {
1473                    classpath = args[++i];
1474                } else if (arg.equals("-d") && i + 1 < args.length) {
1475                    classoutdir = args[++i];
1476                } else if (arg.startsWith("-")) {
1477                    int n = c.isSupportedOption(arg);
1478                    if (n < 0) throw new IllegalArgumentException(arg);
1479                    options.add(arg);
1480                    while (n > 0) options.add(args[++i]);
1481                } else if (arg.endsWith(".java")) {
1482                    files.add(new File(arg));
1483                }
1484            }
1485
1486            if (classoutdir != null) {
1487                fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir)));
1488            }
1489
1490            if (classpath != null) {
1491                Collection<File> path = new ArrayList<File>();
1492                for (String p: classpath.split(File.pathSeparator)) {
1493                    if (p.isEmpty()) continue;
1494                    File f = new File(p);
1495                    if (f.exists()) path.add(f);
1496                }
1497                fm.setLocation(StandardLocation.CLASS_PATH, path);
1498            }
1499            Iterable<? extends JavaFileObject> fos = fm.getJavaFileObjectsFromFiles(files);
1500
1501            JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos);
1502            final Trees trees = Trees.instance(task);
1503
1504            final DPrinter dprinter = new DPrinter(out, trees);
1505            dprinter.source(showSource)
1506                    .emptyItems(showEmptyItems)
1507                    .nulls(showNulls)
1508                    .positions(showPositions)
1509                    .treeSymbols(showTreeSymbols)
1510                    .treeTypes(showTreeTypes);
1511
1512            if (before.isEmpty() && after.isEmpty()) {
1513                if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes)
1514                    after.add(TaskEvent.Kind.PARSE);
1515                else
1516                    after.add(TaskEvent.Kind.ANALYZE);
1517            }
1518
1519            task.addTaskListener(new TaskListener() {
1520                public void started(TaskEvent e) {
1521                    if (before.contains(e.getKind()))
1522                        handle(e);
1523                }
1524
1525                public void finished(TaskEvent e) {
1526                    if (after.contains(e.getKind()))
1527                        handle(e);
1528                }
1529
1530                private void handle(TaskEvent e) {
1531                    JCCompilationUnit unit = (JCCompilationUnit) e.getCompilationUnit();
1532                     switch (e.getKind()) {
1533                         case PARSE:
1534                         case ENTER:
1535                             h.handle(e.getSourceFile().getName(),
1536                                     unit, unit,
1537                                     dprinter);
1538                             break;
1539
1540                         default:
1541                             TypeElement elem = e.getTypeElement();
1542                             h.handle(elem.toString(),
1543                                     unit, (JCTree) trees.getTree(elem),
1544                                     dprinter);
1545                             break;
1546                     }
1547                }
1548            });
1549
1550            task.call();
1551        }
1552
1553        TaskEvent.Kind getKind(String s) {
1554            return TaskEvent.Kind.valueOf(s.toUpperCase());
1555        }
1556
1557        static protected abstract class Handler {
1558            final String name;
1559            Handler(String name) {
1560                this.name = name;
1561            }
1562            abstract void handle(String label,
1563                    JCCompilationUnit unit, JCTree tree,
1564                    DPrinter dprinter);
1565        }
1566
1567        Map<String,Handler> getHandlers() {
1568            Map<String,Handler> map = new HashMap<String, Handler>();
1569            for (Handler h: defaultHandlers) {
1570                map.put(h.name, h);
1571            }
1572            return map;
1573        }
1574
1575        protected final Handler[] defaultHandlers = {
1576            new Handler("trees") {
1577                @Override
1578                void handle(String name, JCCompilationUnit unit, JCTree tree, DPrinter dprinter) {
1579                    dprinter.printTree(name, tree);
1580                    dprinter.out.println();
1581                }
1582            },
1583
1584            new Handler("doctrees") {
1585                @Override
1586                void handle(final String name, final JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1587                    TreeScanner ds = new DeclScanner() {
1588                        public void visitDecl(JCTree tree, Symbol sym) {
1589                            DocTree dt = unit.docComments.getCommentTree(tree);
1590                            if (dt != null) {
1591                                String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1592                                dprinter.printDocTree(label, dt);
1593                                dprinter.out.println();
1594                            }
1595                        }
1596                    };
1597                    ds.scan(tree);
1598                }
1599            },
1600
1601            new Handler("symbols") {
1602                @Override
1603                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1604                    TreeScanner ds = new DeclScanner() {
1605                        public void visitDecl(JCTree tree, Symbol sym) {
1606                            String label = (sym == null) ? Pretty.toSimpleString(tree) : sym.name.toString();
1607                            dprinter.printSymbol(label, sym);
1608                            dprinter.out.println();
1609                        }
1610                    };
1611                    ds.scan(tree);
1612                }
1613            },
1614
1615            new Handler("types") {
1616                @Override
1617                void handle(String name, JCCompilationUnit unit, JCTree tree, final DPrinter dprinter) {
1618                    TreeScanner ts = new TreeScanner() {
1619                        @Override
1620                        public void scan(JCTree tree) {
1621                            if (tree == null) {
1622                                return;
1623                            }
1624                            if (tree.type != null) {
1625                                String label = Pretty.toSimpleString(tree);
1626                                dprinter.printType(label, tree.type);
1627                                dprinter.out.println();
1628                            }
1629                            super.scan(tree);
1630                        }
1631                    };
1632                    ts.scan(tree);
1633                }
1634            }
1635        };
1636    }
1637
1638    protected static abstract class DeclScanner extends TreeScanner {
1639        @Override
1640        public void visitClassDef(JCClassDecl tree) {
1641            visitDecl(tree, tree.sym);
1642            super.visitClassDef(tree);
1643        }
1644
1645        @Override
1646        public void visitMethodDef(JCMethodDecl tree) {
1647            visitDecl(tree, tree.sym);
1648            super.visitMethodDef(tree);
1649        }
1650
1651        @Override
1652        public void visitVarDef(JCVariableDecl tree) {
1653            visitDecl(tree, tree.sym);
1654            super.visitVarDef(tree);
1655        }
1656
1657        protected abstract void visitDecl(JCTree tree, Symbol sym);
1658    }
1659
1660    // </editor-fold>
1661
1662}
1663